I have a variable like LINE=foo,bar,,baz
I tried to split this with delimiter ,
using 2 different techniques:
array=(${LINE//,/ })
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.)
CodePudding user response:
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")'
CodePudding user response:
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
CodePudding user response:
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.