A function cannot affect its caller's positional parameters. This is by design: positional parameters are meant to be private to the function.
Make your function work on an array.
myfunction () {
local _myfunction_arrayname=$1
shift
… # work on the positional parameters
eval "$_myfunction_arrayname=(\"\$@\")"
}
myfunction foo "$@"
set -- "${foo[@]}"
In ksh93 and bash, there's a roundabout way to do something approaching by combining an alias and the .
(source
) builtin with a process substitution. Example.
alias myfunction='. <(echo myfunction_body \"\$@\"; echo set -- "\"\${new_positional_parameters[@]}\"")'
Put the meat of the work of the function in myfunction_body
and make it set the array new_positional_parameters
. After a call to myfunction
, the positional parameters are set to the values that myfunction_body
puts in new_positional_parameters
.
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
You can use the same format as for any other array. To extract the 2nd and 3rd elements from
$@
, you would do: