Reading a space-delimited string into an array in Bash
Solution 1
In order to convert a string into an array, create an array from the string, letting the string get split naturally according to the IFS
(Internal Field Separator) variable, which is the space char by default:
arr=($line)
or pass the string to the stdin of the read
command using the herestring (<<<
) operator:
read -a arr <<< "$line"
For the first example, it is crucial not to use quotes around $line
since that is what allows the string to get split into multiple elements.
See also: https://github.com/koalaman/shellcheck/wiki/SC2206
Solution 2
In: arr=( $line )
. The "split" comes associated with "glob".
Wildcards (*
,?
and []
) will be expanded to matching filenames.
The correct solution is only slightly more complex:
IFS=' ' read -a arr <<< "$line"
No globbing problem; the split character is set in $IFS
, variables quoted.
Solution 3
Try this:
arr=(`echo ${line}`);
Solution 4
If you need parameter expansion, then try:
eval "arr=($line)"
For example, take the following code.
line='a b "c d" "*" *'
eval "arr=($line)"
for s in "${arr[@]}"; do
echo "$s"
done
If the current directory contained the files a.txt
, b.txt
and c.txt
, then executing the code would produce the following output.
a
b
c d
*
a.txt
b.txt
c.txt
Related videos on Youtube
Nikola Novak
Updated on July 08, 2022Comments
-
Nikola Novak almost 2 years
I have a variable which contains a space-delimited string:
line="1 1.50 string"
I want to split that string with space as a delimiter and store the result in an array, so that the following:
echo ${arr[0]} echo ${arr[1]} echo ${arr[2]}
outputs
1 1.50 string
Somewhere I found a solution which doesn't work:
arr=$(echo ${line})
If I run the echo statements above after this, I get:
1 1.50 string [empty line] [empty line]
I also tried
IFS=" " arr=$(echo ${line})
with the same result. Can someone help, please?
-
codeforester about 6 yearsSee this answer on Unix & Linux Stack Exchange: Using sed with herestring (<<<) and read -a.
set -f; arr=($string); set +f
seems to be faster thanread -r -a <<< $string
. -
Gabriel Staples over 2 yearsRelated: how to convert a newline-delimited string to a bash array: Convert multiline string to array
-
Gabriel Staples about 2 yearsSee also these demonstrations and examples here:
shellcheck
SC2206: Quote to prevent word splitting/globbing, or split robustly withmapfile
orread -a
.
-
-
Banjer over 10 yearsand to do a sanity check of your beautiful new array:
for i in ${arr[@]}; do echo $i; done
-
Banjer over 10 yearsor just
echo ${arr[@]}
-
Keith Hughitt over 9 yearsNice -- This solution also works in Z shell where some of the other approaches above fail.
-
Tino over 9 yearsBoth ways may fail if
$line
has globbing characters in it.mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}
gives 3 -
Zorf about 9 yearsThe looping is wrong, it splits the array fine and the pipe into
tr
is superfluous but it should loop over"${arr[@]}"
instead, not$arr
-
Dave over 8 years
declare -a "arr=($line)"
will ignoreIFS
delimiters inside quoted strings -
georg about 8 yearsBoth solutions work for me on the cmd-line.
arr=($line)
doesn't work for me within a bash script whereasread -a arr <<<$line
does. -
Awknewbie almost 8 yearsWhat need to be done if the file was delimited eg :"1,1.50,string" . Can delimite be specified before feeding to array.
-
kev almost 8 years@Awknewbie try this command:
arr=($(echo '1,1.50,string' | tr ',' ' '))
-
vr3C over 7 yearsIts does the work, could you please explain why it works?
-
Manuel Rozier over 7 yearsWorks also with ksh. Beware that declaring
arr=("a b")
won't work, you need to explicitly declare the intermediary variable "line".line="a b"
thenarr=($line)
-
Tim Bird over 7 yearsYou can avoid wildcard expansion with: set -f && arr=($line) && set +f
-
Johnny Wong over 6 years@Tino No. When
line='*'
,read -a arr <<<$line
always work, but onlyarr=($line)
fails. -
Tino over 6 years@JohnnyWong Good find! Sorry that I mixed that with
ksh
wherea='*'; read -A b <<<$a
fails whilea='*'; read -A b <<<"$a"
works. Note thatbash
usesread -a
whileksh
usesread -A
. -
Johnny Wong over 6 yearsRemark: this doesn't work either when the line have '*' in it, like
line='*'
-
codeforester about 6 yearsThis should be the accepted answer. The statement
arr=($line)
in the accepted answer suffers from globbing issues. For example, try:line="twinkling *"; arr=($line); declare -p arr
. -
codeforester about 6 yearsQuoting is optional for herestring,
<<<
but it may be a good idea to still use double quotes for consistency and readability. -
artu-hnrq about 3 yearsLooking for a
GNU Make 4.2.1
solution, but is not that -
artu-hnrq about 3 yearsLooking for a
GNU Make 4.2.1
solution, but it doesn't did the job -
done about 3 years@artu-hnrq Make use the
sh
shell. That shell has no arrays. The question is about arrays. Can't give you an answer compatible with both requirements. Unless you claim that the positional arguments are the only array insh
and, then, this:set -- $line; printf '%s\n' "$@"
would work. Note that glob characters are still a problem in this case. -
artu-hnrq about 3 yearsYou are right @Isaac! I made my own question
-
TonyH about 3 yearsShellcheck SC2207 argues against
arr=($line)
. I like how concise this is, but maybe it's not worth using? -
elulcao almost 3 yearsThis solution worked for me, thanks a lot.
-
Gabriel Staples about 2 years
-
Togomi almost 2 yearsVery simple solution for CentOS8