Use of the Internal Field Separator when capturing array data from a command in a bash script

StackOverflow https://stackoverflow.com/questions/13453052

  •  30-11-2021
  •  | 
  •  

Question

When I run the command

git cherry origin/Server_Dev

in my git repository, I get a list of commits of the form

+ 95b117c39869a810595f1e169c64e728d2d7443d
+ e126f1b996ecf1d2a8cf744c74daa92cce338123
+ 869169a6cb0bbe8f1922838798580a1e74ec3884
+ 667819b617c88bd886dc2001f612b5c7a4d396c3
+ fd41328a84b0a127affa6fe4328c93e933de378c
+ cfe1807e5d4acc6b5e75f4463dadb3b1c957376f

This is a good thing.

I now want to execute this command from within a bash script and capture the output into an array using the following code:

commit_hashes=(`git cherry origin/Dev`)
echo ${commit_hashes[@]}

which yields the following output:

+ 95b117c39869a810595f1e169c64e728d2d7443d + e126f1b996ecf1d2a8cf744c74daa92cce338123 + 869169a6cb0bbe8f1922838798580a1e74ec3884 + 667819b617c88bd886dc2001f612b5c7a4d396c3 + fd41328a84b0a127affa6fe432
8c93e933de378c + cfe1807e5d4acc6b5e75f4463dadb3b1c957376f

This is not a good thing

My list of commits is being returned as a string which I must first break up before I can use it. After some searching I found out that if I add IFS="" to my script before the capturing of the data, my problems would be solved.

So I edited my code to read

IFS=""
commit_hashes=(`git cherry origin/Dev`)
echo ${commit_hashes[@]}

which output

+ 95b117c39869a810595f1e169c64e728d2d7443d
+ e126f1b996ecf1d2a8cf744c74daa92cce338123
+ 869169a6cb0bbe8f1922838798580a1e74ec3884
+ 667819b617c88bd886dc2001f612b5c7a4d396c3
+ fd41328a84b0a127affa6fe4328c93e933de378c
+ cfe1807e5d4acc6b5e75f4463dadb3b1c957376f

This completely ended my sense of reality.

I like to know why things are doing what they're doing, so after some more searching I found out that this is called the Internal Field Separator and it is used on Unix systems by command interpretors to figure where to break patterns up into tokens.

This I understand.

What I don't understand is

  1. Why setting this variable to an empty string allowed it to handle my array data in a sane manner.
  2. Why I had to set it so in the first place, instead of the interpretor realising it was dealing with array data and handling it appropriately.
  3. What effect setting the Internal Field Separator to an empty string will have in the grand scheme of things, since by default it contains the characters for a space, a tab and a newline.

Some help in getting my head around these three points would be appreciated.

Was it helpful?

Solution

See man bash/Arrays. Everything is fine with your array. When you do

echo ${commit_hashes[@]}

echo shows all array elements on one line, as it is told to. When you say

for i in `seq 10`; do
    echo ${commit_hashes[$i]}
done

you will see that just one entry per line is shown.

When you set IFS= to an empty string however, the result of git cherry isn't broken up into multiple values. The whole string including the newlines is assigned to the first array element. If you

echo ${commit_hashes[0]}

in your second case, you will see, that echo shows all output lines.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top