letsc
letsc

Reputation: 2567

bash associative key with a Variable key

Im trying to create an array and then get the value of a key using the following commands:

declare -A email_addresses
mail_address=(["dev"]="dev.com" ["sandbox"]="sandbox.com")
env=$(#command to get env) # result is "sandbox"
echo ${email_address[$env]}

However it keeps throwing this error at me : -bash: "hsandbox": syntax error: operand expected (error token is ""sandbox"")

Im not sure how to get past this. If I do echo $env it returns "sandbox" and not ""sandbox"" so Im not sure what seems to be the issue.

Upvotes: 0

Views: 42

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295472

Fix your "command to get env" to not be emitting literal quotes in its output. Barring that:

# strip leading and trailing quotes from env
env=${env%'"'}; env=${env#'"'}

echo "${email_address[$env]}"

Python-Audience-Friendly Explanation

To explain this in a manner that makes sense to folks who know Python (since that's where most of the OP's rep comes from):

echo "$foo" in shell behaves like the Python command print str(foo), not the Python command print repr(foo).

Consider the following REPL session:

>>> mail_address = { "dev": "dev.com", "sandbox": "sandbox.com" }
>>> env = getSomething()
>>> print str(env)
"dev"
>>> print mail_address[env]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: '"dev"'
>>> print repr(env)
'"dev"'

You've got the exact same problem: Your dictionary contains dev as its literal contents, but your key's literal contents are "dev".


Avoiding Confusion In The Future: Unambiguously Printing Shell Variables

If you want to print a variable's contents in shell in a way that's unambiguous (in the same respect in which print repr(env) is unambiguous in Python), echo is the wrong tool for the job. Consider instead one of the following:

$ declare -p env           ## caveat: doesn't work for all non-printable characters
declare -- env="\"dev\""
$ printf 'env=%q\n' "$env" ## caveat: doesn't work for non-string datatypes
env=\"dev\"

An Aside: Why You Should Always Quote Arguments To echo (Or Not Use It)

While it looks innocuous, the code

echo $foo

actually has surprisingly complicated behavior. Consider the following:

foo=$'\thello\tworld\t*\n\\text'

That's the bash equivalent to the following Python:

foo='\thello\tworld\t*\n\\text'

Now, let's see what happens if you actually use echo to print it with echo $foo, if you have a default value for IFS and your shell is bash:

  • The first tab disappears altogether
  • The other tabs are replaced by spaces
  • The newline literal is replaced by a space
  • The * is replaced by a list of files in the current directory.

That is to say, the behavior in bash of echo $foo is equivalent to the following Python:

import itertools, glob
foo='\thello\tworld\t*\n\\text'
print ' '.join(itertools.chain(*[ glob.glob(s) for s in foo.split() ]))

By contrast, consider:

echo "$foo"

In that case, you'll get the expected behavior... in bash.

Why "in bash"? Because the POSIX standard for echo doesn't specify behavior when any backslash literal is included in the text. echo could do literally anything in this circumstance and still be POSIX-compliant, and BSD-style implementations will behave differently than XSI-style ones do.

Upvotes: 2

Related Questions