Search code examples
gitbashglob

Bash wildcard (*) in command causes in correct output to be captured


Excuse the wording of the title, I'm not sure how to have a catchy title for this 'issue'.

If I run the following command in my terminal (Running MacOS Sierra 10.12.6) git branch --list [rR]elease*

It produces the following expected result

* Release-x
  release-1
  release-2
  release-3

However, If I put the following in a bash script

branches=($(git branch --list [rR]elease*))

for branch in "${branches[@]}"
do
  echo "Found branch $branch"
done

It seems to take the * and echo the branches found and every file/directory name in my current working directory.

Found branch README.md
Found branch acceptance-test
Found branch build
Found branch build.gradle
Found branch flow.sh
Found branch gradle
Found branch gradle.properties
Found branch gradlew
Found branch gradlew.bat
Found branch performance-tests
Found branch postman
Found branch service
Found branch settings.gradle
Found branch sonar-project.properties
Found branch Release-x
Found branch release-1
Found branch release-2
Found branch release-3

Why do the outputs differ? Currently, this breaks the logic of the script as it expects branches. I want to avoid having redundant checks (check if this is an actual branch) cluttering the script if possible.

Edit: I've tried quoting the * and it produces the same result as above.

Visual version of the problem


Solution

  • $(git...) undergoes pathname expansion before it's stored in your array. * branchname marks the current branch in git. That * in the output of the git command expands to all files in your current directory when the array branches is constructed.

    You can turn pathname expansion off with set -f. Also, you have to set $IFS to just a <newline>, otherwise lines with a whitespace would get split into more items (*<space>branchname would become * and branchname):

    old_IFS=$IFS
    IFS=$'\n'   
    set -f
    branches=($(git branch --list '[rR]elease*'))    
    set +f   
    IFS=$old_IFS
    

    Or the better way is to use readarray:

    readarray -t branches < <(git branch --list '[rR]elease*')
    

    Or you can use a while loop with read. This will also trim the leading spaces. If that is not desired, use IFS= read -r ...:

    branches=()
    while read -r branch; do
        branches+=("$branch")
    done < <(git branch --list '[rR]elease*')