How to remove new line added by readarray when using a delimiter?
The implicit trailing new-line character is not added by the readarray
builtin, but by the here-string (<<<
) of bash
, see Why does a bash here-string add a trailing newline char?. You can get rid of that by printing the string without the new-line using printf
and read it over a process-substitution technique < <()
readarray -td, ARR < <(printf '%s' "$VAR")
declare -p ARR
would properly generate now
declare -a ARR=([0]="a" [1]="b" [2]="c" [3]="d")
You could use split+glob (what happens when you leave an expansion unquoted in list contexts). It gets in our way most of the time, it would be a shame not to use it when we actually need it:
IFS=,
set -o noglob
ARR=($VAR) # split+glob with glob disabled, and split using , as delimiter
That's a bit less convoluted than writing a temp file and then call readarray
on it like in the readarray <<< "$string"
approach (also note that readarray -d
needs a very recent version of bash
).
Note that despite the S
in IFS
(which stands for separator), that works the same way as readarray
in that a,,b,
is split into "a"
, ""
and "b"
only.
For a real splitting operator, you could use zsh
instead:
ARR=("${(@s:,:)VAR}")
(the @
and double quotes to preserve the empty elements).
A canned version of @StéphaneChazelas' answer:
# usage: setarray varname sep string
setarray(){ declare -n a=$1; local IFS=$2 -; set -f; a=($3); }
$ setarray arr , 1,2,3,
$ declare -p arr
declare -a arr=([0]="1" [1]="2" [2]="3")
$ setarray path : "$PATH"
$ setarray ld_preload ': ' "$LD_PRELOAD" # its elements can be separated by either ':' or spaces
...
The local -
will make options like set -f
(noglob
) local to the function, just as variables.
The declare -n a=$1
will create a local variable a
as an alias to the global variable named by $1
(the first argument to the function).