I want to write a script that will run

git diff --name-status master..<BRANCH>

but when I run this:

for i in $(git branch | grep -v master); do
   echo $i;

I get echo one directory because git branch echo asterisk (I have one directory in current directory)


Why * is expanded and how can I prevent that expansion?

UPDATE: I can prevent this by using this:

for i in $(git branch | tr -d '*' | grep -v master);

But why is this happening? Why I need to remove asterisk?

  • You are missing quotes " " – Valentin Bajrami Aug 19 '14 at 10:17
  • @val0x00ff where? – jcubic Aug 19 '14 at 10:19

Unquoted variables and command substitutions like $i or $(git …) apply the split+glob operator to the string result. That is:

  1. Build a string containing the value of the variable or the output of the command (minus final newlines in the latter case).
  2. Split the string into separate fields according to the value of IFS.
  3. Interpret each field as a wildcard pattern and replace it by the list of matching file names; if a pattern doesn't match any file, leave it intact.

The output of git branch | grep -v master (step 1) contains * master which is split (step 2) into two fields * and master; * is replaced (step 3) by the list of file names in the current directory.

You can run set -f to temporarily disable globbing. Another approach is to avoid command substitution and instead parse the input with read. Neither do the right thing though — you'll have spurious branch names, because the git output contains more than what you need (the * flag to indicate the current branch, but also things like remotes/somewhere/foo -> bar for remote-tracking branches). I think the following is safe if inelegant:

for i in $(git branch | sed -e 's/^..//' -e 's/ .*//'); do
   echo $i

I think the robust way is to use git-for-each-ref.

for i in $(git for-each-ref --format='%(refname:short)' refs/heads refs/remotes); do
  echo $i

Text streams like this should be read using a while loop rather than for, which is probably causing the issue (although I cannot reproduce it). A simple way to do this:

git branch | while IFS= read -r line
    echo "${line:2}"


$ cd -- "$(mktemp -d)"
$ git init
Initialized empty Git repository in /tmp/tmp.MJFmu7q7EH/.git/
$ touch README
$ git commit --allow-empty -m "Initial commit"
[master (root-commit) da46b03] Initial commit
$ git branch foo
$ git branch
* master
$ for i in $(git branch)
> do
>    echo $i
> done
$ git branch | while IFS= read -r line
> do
>     echo "${line:2}"
> done
  • Have the same with while, I'm using GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu). – jcubic Aug 20 '14 at 8:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.