CrackerJack9
CrackerJack9

Reputation: 3651

bash indirect reference by reference

A lot of similar questions, but hadn't found one for using a variable in the name this way:

#!/bin/bash

# $1 should be 'dev' or 'stg'

dev_path="/path/to/123"
stg_path="/path/to/xyz"

# Use $1 as input to determine which path variable to 'execute'
${!\$1'/morepath'}

Using $1, I want to be able to reference either $dev_path or $stg_path ($1 == 'dev' or $1 == 'stg') and be able to reference the value of $1_path which would be '/path/to/123' or '/path/to/xyz'

so the result would either be:

'/path/to/123/morepath' or '/path/to/xyz/morepath'

based upon $1 being 'dev' or 'stg'.

I've tried various iterations of using ! and \$ in various places from other posts, but no luck

Upvotes: 1

Views: 583

Answers (3)

konsolebox
konsolebox

Reputation: 75568

I think that would be unsafe. If $1 gets a value that's not dev or stg it would cause syntax error and other unexpected things may happen. Even with eval it wouldn't be a good idea unless you add a conditional filter. You could use a case statement:

case "$1" in
dev)
    "$dev_path"/bin/execute
    ;;
std)
    "$std_path"/bin/execute
    ;;
*)
    echo "Invalid argument: $1"
    ;;
esac

Or make sure it's valid and use eval:

[[ $1 == dev || $1 == std ]] && eval "\"\${${1}_path}/bin/execute\""

Using if ... elif ... could be valid too but the case method is simpler.

As for variable indirection you would need to store "${1}_path" to another variable first which is unnecessary.

You could also use dev|std) eval ... ;; in the case statement at your preference.

Upvotes: 3

Adam Rosenfield
Adam Rosenfield

Reputation: 400512

See the Bash manual section on shell parameter expansion:

If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix } and ${!name[@]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.

[...]

Since you also want to modify the name (by suffixing _path) before expanding again, you need to go through another variable:

# $1 should be 'dev' or 'stg'
dev_path="/path/to/dev"
stg_path="/path/to/stg"

path=${1}_path   # path is now either 'dev_path' or 'stg_path'

# Run either /path/to/dev or /path/to/stg
${!path}/bin/execute

Of course, if both of the dev and stg programs are in the same directory, then there's no need for all this, you can just directly expand $1:

/path/to/$1/bin/execute

Upvotes: 6

Cfreak
Cfreak

Reputation: 19319

Why the need for a "variable, variable"? Why not

MYPATH="/path/to/$1"
$MYPATH/bin/execute

Upvotes: 0

Related Questions