Is there a more compact alternative to
arr=( 1 2 3 )
e1=${arr[0]}
e2=${arr[1]}
e3=${arr[2]}
?
Something like,
e1, e2, e3=${arr[@]}
Generally speaking, asking this question implies that you shouldn't be using an array for your data in the first place.
That said, the following function is reusable and correct -- with no caveats around which data it can and can't be used for:
array_to_vars() {
declare -n _arr=$1
local var
for var; do
shift || return
printf -v "$var" %s "$1"
done
}
...usable as:
# put first element of arr into e1, second into e2, third into e3
# disregard the rest
array_to_vars arr e1 e2 e3
It's not as short as one might like, but it's less likely to cause bugs as something that works only for data not containing a sigil.
Let's say you're populating it like so:
read -r -a arr < <(command-that-generates-a-list)
You could replace that with:
read -r e1 e2 e3
Or let's say it's:
arr=( )
while read -r line; do
arr+=( "$line" )
done < <(command-that-generates-a-list)
You could that replace that with:
{ read -r e1; read -r e2; read -r e3; } < <(command-that-generates-a-list)
or with:
{ IFS=$'\n' read -r -d '' e1 e2 e3; } < <(command-that-generates-a-list && printf '\0')
Or let's say it's:
arr=(${string//,/ })
...in that case, it would be simpler and more correct (avoiding undesired behaviors like glob expansion -- see BashPitfalls #50) to use:
IFS=, read -r e1 e2 e3 <<<"$string"
_arr declared in the function array_to_vars isn't used at all.If you don't have whitespaces in your array element then you can use read using default IFS value (whitespace) in shell:
arr=( 1 2 3 )
# unset IFS to default value it has been set earlier
unset IFS
# read content in 3 variables
read e1 e2 e3 <<< "${arr[*]}"
# examine the content of variables
declare -p e1 e2 e3
declare -- e1="1"
declare -- e2="2"
declare -- e3="3"
<<< "${arr[@]}" is well into the area of unspecified behavior. I'd at least suggest <<< "${arr[*]}" to be explicit to readers about how this works (putting the first character of $IFS between each element), and to reduce the syntactic ambiguity. (I'd also suggest read -r to avoid mangling backslashes, and perhaps specifying a single-character value for IFS to reduce the number of potential datums that will cause values to be read incorrectly).
12,343,564. I then convert it to an array of 3 elements:arr=(${input//,/ }). Then I wannna unpackarr.arr=(${...})in the first place.IFS=, read -r one two three _ <<<"$input"is cleaner, more direct, less buggy (for instance, if you hadinput='1,2,*', you'd get anarrwith a list of filenames in it due to glob expansion happening at the same point where string-splitting does). BTW, in the above, the_soaks up any items after the third -- so if you had12,343,565,foobar,baz, thenfoobar,bazwould be assigned to_rather than appended to the same element with565.IFS=, readchangesIFSonly for the duration of the onereadcommand. It doesn't impact any other part of your script.