you should handle that stuff in the index evals. and you can indirect through your indirection variable's indices if you make it an array.
a=(abc1 def2 ghi3 jkl4 mno5)
r=('a[c=${#a[@]}]' a\[i] a\[@])
for i in 0 1 2 3 4 5
do c=
printf "<%s>\n" "${!r-${!r[i<c?1:2]}}"
printf "\n\tindex is $i and count is $c\n\n"
done
<abc1>
index is 0 and count is 5
<def2>
index is 1 and count is 5
<ghi3>
index is 2 and count is 5
<jkl4>
index is 3 and count is 5
<mno5>
index is 4 and count is 5
<abc1>
<def2>
<ghi3>
<jkl4>
<mno5>
index is 5 and count is 5
Because bash
's indices are 0-based, the total count of array objects will always work out to one more than than the highest set index, and so:
c=
echo "${a[c=${#a[@]}]-this index is unset}" "$c"
this index is unset 5
...the parameter expands out to the default word if any is provided.
If one is not provided:
c=
${!r}
echo "$c"
5
...there's no harm done.
In the loop I track an $i
ndex variable and check if it is at least as large as $c
ount. When it is lesser I expand the $r
eference var to a[i]
because it is a valid index, but when it is equal or greater I expand the $r
ef to the entire $a
rray.
Here it is in a function:
ref_arr(){
local index=-1 count=
local ref=( "$1[ count= \${#$1[@]} ]"
"$1[ index ]" "$1[ @ ]"
) && printf "input array '%s' has '%d' members.\n" \
"$1" "${!ref-${count:?invalid array name: "'$1'"}}"
while [ "$((index+=1))" -lt "$count" ]
do printf "$1[$index] == '%s'\n" "${!ref[1]}"
done
}
some_array=(some "dumb
stuff" 12345\'67890 "" \
'$(kill my computer)')
ref_arr some_array
ref_arr '$(echo won'\''t work)'
input array 'some_array' has '5' members.
some_array[0] == 'some'
some_array[1] == 'dumb
stuff'
some_array[2] == '12345'67890'
some_array[3] == ''
some_array[4] == '$(kill my computer)'
bash: count: invalid array name: '$(echo won't work)'
Best Answer
Well,
"${array[@]}"
gives you the values of the array, that's all. I don't think it should have any problems with that.But it doesn't give you anything outside the values, like indexes (as you mention), or other attributes. Bash arrays could be read-only, or have the integer or upper/lowercase attributes. The same of course goes for associative arrays: the result of that assignment would be a regular indexed array, but losing the indexes would be the bigger issue. The attributes would probably be easy, you'd probably know what attributes you've set on the array.
An assignment like
array2=("${array1[@]}")
would remove all the original values ofarray2
, so there's no problem with leftover data. The attributes ofarray2
would be kept though, and if it's set an integer array, the values ofarray2
would be taken as arithmetic expressions. (Same as ina="1 + 3"; declare -i b=$a; echo $b
, which prints "4".)To copy the indexes too, you'd need use a loop (and set the attributes manually):
Or, to get an exact copy, attributes and all, the output of
declare -p
is usable as input to the shell, so this should copyai1
toai2
with all keys and attributes:String operations like
${var/pat/repl}
work on all values. I don't think you should have any other issues with that either. Though I do think the asterisk in your pattern is misplaced as${var/pat/repl}
along with${var##pat}
take the longest match, so"${var/#prefix*/}"
would clear the whole value.You probably want
"${myArray[@]#unwanted-prefix}"
instead.