4

I tried to do the opposite of if in shell to only do something if a value in a hash doesn't exist. I've learned to create a hash in bash from here:Associative arrays in Shell scripts

declare -A myhash

I declared a simple hash:

myhash[$key]="1"

and

[ ${myhash[$key]+abc} ]

to see if myhash[$key] exist or not from here: Easiest way to check for an index or a key in an array?

I also learned to add ! in front of an expression to do the opposite in if clause from here:How to make "if not true condition"?

But the following expression

if ! [ ${myhash[$key]+abc} ]; then
     echo $key

fi

doesn't work and no information is printed. There is no error message.

I tried this:

[ ${myhash[$key]+abc} ] && echo $key

And got the error message:

abc: command not found

Can anyone tell me how to make it work?

Community
  • 1
  • 1
olala
  • 4,146
  • 9
  • 34
  • 44
  • 1
    consider editing your question to include 1. Exact error message you're getting or other evidence of "it doesn't work". 2. a simple test case providing values for `myhash[key]`. The `[ .. ]` construct is documented in most systems with `man test`. It is expecting a command as the result of converting `${myhash[key]+abc}` to a string. Good luck. – shellter Feb 19 '14 at 17:55

3 Answers3

2

First, this

[ ${myhash[$key]+abc} ]

will test if the result of the parameter expansion is empty or not. Either ${myhash[$key]} exists and expands to a string (which itself may or may not be empty), or it does not and it expands to the string "abc". Assuming you don't set myhash[$key]="", the expansion always produces a non-empty string, and so the command succeeds. As a result, ! [ ${myhash[$key]+abc} ] would always fail.

Assuming "abc" is not a valid entry in myhash, you need to actually check if the parameter expands to an actual value, or "abc" for unset keys:

if [[ ${myhash[$key]+abc} == abc ]]; then
    echo "$key does not exist in myhash"
else
    echo "myhash[$key]=${myhash[$key]}"
fi
chepner
  • 497,756
  • 71
  • 530
  • 681
2

Easiest way to check for an index or a key in an array? shows how to check if it exists with [ ${array[key]+abc} ].

If it does, the command exits successfully, so the portion after the && gets executed (echo "exists")

You want to check if it doesn't exist. So you want your command to be executed if the [..] portion exits unsuccessfully. So use || instead of &&:

[ ${myhash[$key]+abc} ] || echo "does not exist"

&&: carry on with next command only if first succeeded

||: only carry on with next command if first did not succeed

Community
  • 1
  • 1
Vuade
  • 33
  • 4
1

The reason nothing is printed is because you check if the value is unset after setting it.

Here's what you're doing:

#!/bin/bash
key=foo

declare -A myhash                     # create associative array
myhash[$key]="1"                      # set the value
if ! [ ${myhash[$key]+abc} ]; then    # check if value is not set
     echo $key                        # if so, print key 
fi

And now you're asking "Why isn't the unset check triggering when the value is set?"

If you instead wanted to check if the key is set, you should not have inverted the existence check using !.

As for [ ${myhash[$key]+abc} ] && echo $key giving abc: command not found, I can't explain that. It would never normally happen.

That is what you would have seen if you did ${myhash[$key]+abc} && echo $key though. Are you sure you're correctly presenting the actual examples you ran, and the actual results you got

that other guy
  • 116,971
  • 11
  • 170
  • 194