Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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?

share|improve this question
You are missing quotes " " – val0x00ff Aug 19 '14 at 10:17
@val0x00ff where? – jcubic Aug 19 '14 at 10:19
up vote 4 down vote accepted

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
share|improve this answer

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
share|improve this answer
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 posting your answer, you agree to the privacy policy and terms of service.

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