help-bash
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]