Log a list of files and open them with vscode CLI (creating a Shell macro)

70 views Asked by At

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 tried 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

There are 2 answers

4
chc On 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
}
0
user1934428 On

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}