I've written a script to list commits in a repo that contain a specific file. It's working perfectly, but I don't understand why I had to write this:
for c in $(git rev-list "$rev_list"); do
git ls-tree --name-only -r "$c" | grep -q "$file"
if [ $? -eq 0 ]; then
echo "Saw $file in $c"
fi
done
Whereas I normally write the same thing like this:
[[ $(git ls-tree --name-only -r "$c" | grep -q "$file") ]] && echo "Saw $file in $c"
# or
[[ ! $(git ls-tree --name-only -r "$c" | grep -q "$file") ]] || echo "Saw $file in $c"
Neither of the short versions work: they don't output anything. When I write it so that it shows all commits that don't contain the file, I do get output:
[[ $(git ls-tree --name-only -r "$c" | grep -q "$file") ]] || echo "Did not see $file in $c"
However, if I then take a commit hash from the output and run
git ls-tree -r <the hash> | grep file
I notice the file is in the tree for some commits, leading me to believe it's just listing all the commits the script processes. Either way, I'm probably missing something, but I can't exactly work out what it is
You don't need to wrap the command in a conditional statement (
[[ $(command) ]]
). In fact, that will never work withgrep -q
, because you're actually testing whether the command prints anything. You can just do this:In general, any code block like
can be replaced with either
or even
Which of the three alternatives you should use depends on whether
foreground_command
,bar
, or both are multi-line commands.awk
to the rescue: