Home > Mobile >  bash string split by delimiter breaks on empty value
bash string split by delimiter breaks on empty value

Time:09-13

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.)

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.

  •  Tags:  
  • bash
  • Related