307

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?

3

6 Answers 6

461

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

Sign up to request clarification or add additional context in comments.

14 Comments

and to do a sanity check of your beautiful new array: for i in ${arr[@]}; do echo $i; done
or just echo ${arr[@]}
Both 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
declare -a "arr=($line)" will ignore IFS delimiters inside quoted strings
@Tino No. When line='*', read -a arr <<<$line always work, but only arr=($line) fails.
|
66

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.

5 Comments

This 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.
Quoting is optional for herestring, <<< but it may be a good idea to still use double quotes for consistency and readability.
I get func:read:5: bad option: -a
@payne, then your shell wasn't bash -- sh isn't guaranteed to support arrays at all. Be sure your script starts with #!/usr/bin/env bash not #!/bin/sh, and that you don't start it with sh scriptname.
61

Try this:

arr=(`echo ${line}`);

7 Comments

Nice -- This solution also works in Z shell where some of the other approaches above fail.
Its does the work, could you please explain why it works?
Remark: this doesn't work either when the line have '*' in it, like line='*'
Looking for a GNU Make 4.2.1 solution, but it doesn't did the job
@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 in sh and, then, this: set -- $line; printf '%s\n' "$@" would work. Note that glob characters are still a problem in this case.
|
18

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

2 Comments

Looking for a GNU Make 4.2.1 solution, but is not that
@artu-hnrq, why would you be looking for a makefile solution in answers to a question that isn't tagged for make and doesn't otherwise mention make in any way?
1

Yet another solution, but using readarray:

readarray -d ' ' arr <<< "argelia china denmark colombia"

Indeed, storing the input in an array of 4 positions:

$ echo ${#arr[@]} ${arr[@]:1:2}
4 china  denmark 

1 Comment

I like readarray, but you usually want to use -t with it. This is easier to see if you declare -p arr instead of using echo.
-9
line="1 1.50 string"

arr=$( $line | tr " " "\n")

for x in $arr
do
echo "> [$x]"
done

1 Comment

The looping is wrong, it splits the array fine and the pipe into tr is superfluous but it should loop over "${arr[@]}" instead, not $arr

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.