6

Given string foo, I want to store each of its field seperated by \n into elements of array bar. And I want to do this using read command, or any other command that is compatible with older versions of bash (which readarray isn't).

I tried this command:

IFS=$'\n' read -d '' -r -a bar <<< "$foo"

but it just returns error code 1.

Is there any command that I can use to accomplish what I want? I know I could do this iteratively but obviously just doing it with one command is preferred.

2 Answers 2

4

read is returning 1 because the delimiter is not seen in the string. However, the array is populated:

$ echo "$BASH_VERSION"
3.2.57(1)-release
$ foo=$'one\ntwo\nthree\nfour'

$ IFS=$'\n' read -d '' -r -a bar <<<"$foo"
$ echo $?
1
$ declare -p bar
declare -a bar='([0]="one" [1]="two" [2]="three" [3]="four")'

Using a non-null delimiter produces a non-zero result:

$ unset bar
$ IFS=$'\n' read -d "\034" -r -a bar <<<"${foo}\034"
$ echo $?
0
$ declare -p bar
declare -a bar='([0]="one" [1]="two" [2]="three" [3]="four")'

Octal 34 is the ASCII "file separator" character, and is unlikely to be present in your data.

3

A slightly shorter variant of @glenn jackman's first solution: given

foo=$'one\ntwo\nthree\nfour'

, we let Bash do all the work:

set -o noglob         # See special Note, below.
IFS=$'\n' bar=($foo)
set +o noglob         # See special Note, below.

The parentheses tell Bash that we are initializing an array, whose elements are what's inside the parentheses. That's it, done.

Edited to add      Note: if input lines could contain globbing metacharacters like * or ? (man 7 glob has the full list), then we must guard against filename expansion; by, for example, temporarily disabling noglob. Thank you for catching that, Gordon Davisson!



Confirm that worked:

echo ${#bar[@]}
4

, and

echo "[0]:'${bar[0]}' ... [3]:'${bar[3]}'"
[0]:'one' ... [3]:'four'


echo "$BASH_VERSION"
4.1.2(2)-release
2
  • This can fail if any of the lines look like filename wildcards. For example, if there's a line consisting just of "*", it'll be replaced by a list of files in the current directory. Jan 11, 2021 at 7:16
  • Well caught; thank you! To guard against that eventuality, we can temporarily disable noglob. Editing... Jan 11, 2021 at 8:09

You must log in to answer this question.