9
VAR=a,b,c,d
# VAR=$(echo $VAR|tr -d '\n')
echo "[$VAR]"
readarray -td, ARR<<< "$VAR"
declare -p ARR

Result:

[a,b,c,d]
declare -a ARR=([0]="a" [1]="b" [2]="c" [3]=$'d\n')

How can I tell readarray not to add the final newline \n? What is the meaning of the latest $ symbol?

10

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")
  • 3
    Wow! I would have never found this. Thanks – user1156544 May 20 at 10:25
4

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

  • The readarray <<< "$string" writes to a tempp file and then deletes it instead of using the memory? – user1156544 May 20 at 11:34
  • @user1156544 Yes. – mosvy May 20 at 12:03
  • How can I do something similar to your last command in bash? I am using bash 3.3 and trying to compensate the lack of readarray -d – user1156544 May 23 at 19:26
3

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.