skip to Main Content

I’m trying to create a macro on my shell.

The operation I’m trying to automate is this one:

Find all the files containing TEXT_TO_SEARCH, and open them with VSCODE

I can do this with a one-liner

$ code `git grep TEXT_TO_SEARCH | cut -d: -f1 | sort -u`

so my first step was adding the following function to ~/.zshrc

cgrep() {
  code `git grep "$1" | cut -d: -f1 | sort -u`
}

and then

$ cgrep TEXT_TO_SEARCH

This works.

Now I’m trying to add an extra feature:

Before opening each file with VSCode, echo to the console "Opening FILE_NAME"

First I’ve tryied this

cgrep() {
  grep_results=`git grep "$1" | cut -d: -f1 | sort -u`
  for file in $grep_results; do
    echo "Opening $file"
    code $file
  done
}

Note that grep_results is a "vertical list" i.e.

$ echo $grep_results

src/path1/FILE1.py
src/path2/FILE2.py
src/path3/FILE3.py

This way the for loop considers the first file as the whole grep_results and it opens FILE3.py (not src/path3/FILE3.py).

I’ve also tryied this (with the help of GPT)

cgrep() {
  grep_results=`git grep "$1" | cut -d: -f1 | sort -u`
  echo "$grep_results" | while read -r file; do
    echo "Opening $file"
    code "$file"
  done
}

This way I can open just the first grepped file, and I get a message I don’t want from VSCode and I don’t actually understand

$ cgrep TEXT_TO_SEARCH

Opening src/path1/FILE1.py
Run with 'code -' to read from stdin (e.g. 'ps aux | grep code | code -').

2

Answers


  1. Chosen as BEST ANSWER

    Solved, with the help of @Gilles 'SO- stop being evil' in Unix&Linux StackExchange (his full answer here).

    This is my final version

    cgrep() {
        grep_results=(`git grep -l $1`)
        for file in "${grep_results[@]}"; do
            echo "Opening $file"
            code $file
        done
    }
    

  2. Your loop is executed exactly once (as you can see when you run the code with -x turned on), because you have only a single variable in the list, $grep_results. You could split the variable on white space (i.e. the newlines in the variable) by writing

    for file in ${(z)grep_results}
    

    but this still would fail, if one of the files contains embedded spaces. This problem also exists in your own "final version", where you replaced the variable by an array.

    What you really want to do, is follow your original approach, but split the result of your pipeline by newlines and not white space:

    for file in ${(f)grep_results}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search