2

When I run the following code

declare -A X # get an associative array
index="a'b" # a somewhat weird index
X[$index]="this is set"
echo "<<${X[$index]}>>"
if test -v X[$index]; then # behaves in an unexpected way
  echo indeed, this is set
else
  echo no, it is not
fi

the result is no, it is not in my bash version 5.1.16(1). As soon as i remove the single quote from the index, it works as expected, telling that indeed, this is set.

From the bash manual:

Indexed arrays are referenced using integers [...]; associative arrays use arbitrary strings.

Given that I can properly use the index to set and retrieve the value, I wonder if this is a bug in test -v or if there is some explanation why this does not work or whether different quoting can get test -v to work. (I could use test -z in this particular case, but the question is about -v).

5
  • 1
    test -v 'X[$index]'. It looks weird, but that's what you'll use. A real answer would explain why.
    – Kusalananda
    Commented 2 days ago
  • 1
    Oh, wow, this is weird indeed. And for all I know about bash, this I would have felt stupid to even try this. This looks like test -v does its own parsing of stuff, a hint about which seems missing in the documentation.
    – Harald
    Commented 2 days ago
  • Would you agree that this is a duplicate of unix.stackexchange.com/q/677909/116858 ?
    – Kusalananda
    Commented 2 days ago
  • @Kusalananda Hmm, not really a duplicate, maybe related. But closing and saying that this other question has an answer that works here too, seems right.
    – Harald
    Commented 2 days ago
  • The accepted answer there seems to cover your case exactly, so I will close this as a duplicate. Thank you.
    – Kusalananda
    Commented 2 days ago

1 Answer 1

1

The way the expansion happens is not how you would expect.

test -v X[$index]

Does not expand to:

test -v X["a'b"]

But instead it expands like this:

test -v 'X[a'\''b]'

bash splits and escapes the array syntax in a way that prevents test -v from seeing a valid array element. test -v expects a fully valid variable name or array element as a single argument.

As Kusalananda suggested you could use test -v 'X[$index]' however I think a much more correct way would be to use the extended test syntax instead:

if [[ -v X["$index"] ]]; then
10
  • 1
    You would need to use [ -n "$index" ] && [ -v 'X[$index]' ] or [[ -n $index && -v 'X[$index]' ]], or you would have issues with "some values" of keys containing ], backslashes, or being empty. See Stéphane's answer here: unix.stackexchange.com/a/677920/116858
    – Kusalananda
    Commented 2 days ago
  • @Kusalananda Why would -n $index be necessary? If the variable was empty it should still fail. It also seems to handle ] and ]] without quotes.
    – jesse_b
    Commented 2 days ago
  • It would fail, but with the additional "bad array subscript" error.
    – Kusalananda
    Commented 2 days ago
  • @Kusalananda I don't get that
    – jesse_b
    Commented 2 days ago
  • Is the variable you're testing on an associative arrary?
    – Kusalananda
    Commented 2 days ago

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.