2

I have a variable like LINE=foo,bar,,baz

I tried to split this with delimiter , using 2 different techniques:

  1. array=(${LINE//,/ })
  2. array=($(echo "$LINE" | tr ',' '\n'))

echo ${array[2]} should return an empty value but it returns baz (Both treat baz as the 3rd value when it should be the 4th instead.)

4 Answers 4

6

You can do this with read -a and an alternate delimiter:

IFS=, read -a array <<<"$LINE"

Note that since the assignment to IFS is a prefix to the read command, it only applies to that one command, and you don't have to set it back to normal afterward. Also, unlike the ones that depend on word-splitting of unquoted variables, it won't try to "expand" any entries that look like filename wildcards into lists of matching files.

Demo:

$ LINE=foo,bar,,baz
$ IFS=, read -a array <<<"$LINE"
$ declare -p array
declare -a array='([0]="foo" [1]="bar" [2]="" [3]="baz")'
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @Gordon. This works beautifully. There are multiple correct answers. Marking this as correct because of more upvotes.
3

You are relying on a sequence of whitespace between tokens as the separator, but of course, that will lose any empty strings.

As a somewhat crude workaround, temporarily override IFS:

oldIFS=$IFS
IFS=','
array=($LINE)
IFS=$oldIFS

Demo: https://ideone.com/Dd1gUV

Comments

0

By default array treat all 'blank' characters as delimiters. If you need to preserve empty values you have to take care of them first.

line='foo, ,bar,,baz'
line=${line//,,/,null,}
line=${line//,[[:blank:]],/,null,}
array=(${line//,/ })

$ echo "${array[@]}"
foo null bar null baz

$ echo "${array[@]//null/ }"
foo   bar   baz

Comments

-2

You could use mapfile (or readarray, same thing):

$ LINE=foo,bar,,baz
$ declare -a PARTS
$ mapfile -t -d, PARTS <<<"$LINE"
$ declare -p PARTS
declare -a PARTS=([0]="foo" [1]="bar" [2]="" [3]=$'baz\n')

There's an extraneous newline at the end of the 3rd element, hence the $'baz\n' value, so you'd have to handle that (see discussion in comments, though). Not sure where it comes from.

5 Comments

The newline is added automatically by <<<"$LINE"; to avoid that you'd have to use something like < <(printf %s "$LINE") instead.
@GordonDavisson ah, yes, thank you. I should have skimmed the docs on <<< a little.
@GordonDavisson : This was why I suspected as well, but if the newline is added by <<<, wouldn't you then see it also by i.e. printf %s $(cat <<<$LINE)?
@user1934428 command substitutions, i.e., $(...) remove the trailing newline.
@user1934428 also, the docs for <<< read: "The result is supplied as a single string, with a newline appended [...]".

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.