[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Use of $@
From: |
Kerin Millar |
Subject: |
Re: Use of $@ |
Date: |
Tue, 21 Feb 2023 11:03:57 +0000 |
On Tue, 21 Feb 2023 11:27:36 +0100
Christof Warlich <cwarlich@gmx.de> wrote:
> Hi,
>
> just to improve my bash skills: The following functions prints the array
> index of a value if found:
>
> index() { local e="$1"; shift; local a=("$@"); for i in "${!a[@]}"; do
> [[ ${a[$i]} != $e ]] || { echo $i; break; }; done; }
>
> Thus, with e.g.: myarray=("a" "bc" "my value" "z")
>
> I get:
>
> $ index "my value" "${myarray[@]}"
> 2
>
> as expected. The only thing that bothers me is that I couldn't get away
> without the intermediate assignment of $@ to a new array (a): Is there
> really no way to avoid that, i.e. directly using $@ in the for-loop?
Unfortunately, the function is incorrect to begin with.
$ myarray=(foo bar baz)
$ index bar "${myarray[@]}"
1
$ unset -v 'myarray[0]'
$ declare -p myarray
declare -a myarray=([1]="bar" [2]="baz")
$ index bar "${myarray[@]}"
0
Indeed, to correctly encapsulate the intended functionality with a function is
a tremendously awkward affair in bash. One option would be to pass the array by
its name rather than as its expanded elements, then make use of a nameref in
the function. Unfortunately, namerefs are poorly implemented in bash [1] [2].
Should you wish to try it anyway, here is an example.
index() {
local i e="$1"
local -n _ref="$2"
shift
for i in "${!_ref[@]}"; do
if [[ ${_ref[i]} == "$e" ]]; then
printf '%s\n' "$i"
return 0
fi
done
return 1
}
$ declare -p myarray
declare -a myarray=([1]="bar" [2]="baz")
$ index bar myarray
1
One of the many issues with namerefs is that they can easily be undone by a
(variable) name space conflict. I do not know which underlying problem the
function is intended to solve but it is quite possible that, whatever it may
be, you might benefit from using an associative array [1]. Not least, an
associative array could easily be made to store a 'reverse' map of elements to
index numbers.
On the other hand, if you are entirely certain that the function will only ever
have to contend with non-sparse arrays in your program, you could just loop
over the positional parameters ("$@") and use an incrementing counter variable
to identify the appropriate index number.
P.S. The right-hand side of == in [[ is treated as a globbing pattern if not
appropriately quoted.
[1] http://mywiki.wooledge.org/BashFAQ/006
[2] https://gist.github.com/ormaaj/5682807
--
Kerin Millar