Dan
Dan

Reputation: 767

Bash script to convert a string with space delimited tokens to an array

I have a string

echo $STRING

which gives

first second third fourth fifth

basically a list separated spaces.

how do i take that string and make it an array so that

array[0] = first
array[1] = second

etc..

I have tried

IFS=' ' read -a list <<< $STRING

but then when i do an

echo ${list[@]}

it only prints out "first" and nothing else

Upvotes: 15

Views: 22297

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295619

Your original code generally works -- the quoting is a bit off (and how much that matters is version-specific: you wouldn't see your original bug on a newer version of bash), but nothing further.

After:

# assign string
string='this is several words'

# split string to a list
IFS=' ' read -r -a list <<<"$string"

...you can run:

# print a definition of the variable list
$ declare -p list
declare -a list=([0]="this" [1]="is" [2]="several" [3]="words")

# print each item in the list array on a separate line
$ printf ' - %s\n' "${list[@]}"
- this
- is
- several
- words

# still works with echo; change IFS to show that we're really an array
$ IFS=':' echo "${list[*]}"
this:is:several:words

More importantly, it also works in cases where the competing answer doesn't:

# need to be in a non-empty directory to demonstrate
$ touch a.txt b.txt c.txt

# put literal asterisks as separate words in our string
$ string='list * contains * asterisks'

# reading those using read -a works fine
$ IFS=' ' read -r -a list <<<"$string"

# whereas the array=( $string ) is NOT fine
$ IFS=' '; buggyList=( $string )

# print both arrays' contents
$ declare -p list buggyList
declare -a list=([0]="list" [1]="*" [2]="contains" [3]="*" [4]="asterisks")
declare -a buggyList=([0]="list" [1]="a.txt" [2]="b.txt" [3]="c.txt" [4]="contains" [5]="a.txt" [6]="b.txt" [7]="c.txt" [8]="asterisks")

As you can see, the list=( $string ) answer gets filenames injected into its contents, but the read -a list contains exactly the word-split contents of your original string.

Upvotes: 0

svckr
svckr

Reputation: 839

It's simple actually:

list=( $STRING )

Or more verbosely:

declare -a list=( $STRING )

PS: You can't export IFS and use the new value in the same command. You have to declare it first, then use its effects in the following command:

$ list=( first second third )
$ IFS=":" echo "${list[*]}"
first second third
$ IFS=":" ; echo "${list[*]}"
first:second:third

Notice that the last example will change IFS to ":" until you change it again, or the shell exits. Usually you want to use a subshell, or save the original value of IFS so you can restore it afterwards.

Upvotes: 27

Related Questions