1

Assuming we've all read https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html (specifically, search for indirect expansion).

The question means, instead of doing:

alpha_date=1563980822; alpha_hash=bfc1a9ad; alpha_url=http://example.com/bfc1a9ad; alpha_path=/build/alpha; alpha_status=failure; bravo_date=1563981822; bravo_hash=f76025c5; bravo_url=http://example.com/f76025c5; bravo_path=/build/alpha2; bravo_status=success; charlie_date=1563982822; charlie_hash=289f55fd; charlie_url=http://example.com/289f55fd; charlie_path=/build/charlie; charlie_status=success

for prefix in alpha bravo charlie; do
    for suffix in date hash url path status; do
        tempvar="${prefix}_${suffix}"
        echo -n "$tempvar: ${!tempvar}"$'\t'
    done
    echo
done

This works and outputs:

alpha_date: 1563980822      alpha_hash: bfc1a9ad      alpha_url: http://example.com/bfc1a9ad      alpha_path: /build/alpha        alpha_status: failure
bravo_date: 1563981822      bravo_hash: f76025c5      bravo_url: http://example.com/f76025c5      bravo_path: /build/alpha2       bravo_status: success
charlie_date: 1563982822    charlie_hash: 289f55fd    charlie_url: http://example.com/289f55fd    charlie_path: /build/charlie    charlie_status: success

I'd like to skip creating the tempvar something like this:

for prefix in alpha bravo charlie; do
    for suffix in date hash url path status; do
        echo -n "${prefix}_${suffix} is ${!${prefix}_${suffix}}"$'\t'
    done
    echo
done

But of course I get a bad substitution error from bash.

Is there any way to do bash "indirect expansion" on a "string"?

  • This question would be a poster child for why we should be using arrays. – muru Jul 24 '19 at 15:31
  • Of course my example is contrived. In the real situation arrays are not an option. – Bruno Bronosky Jul 24 '19 at 15:40
  • 1
    Because the code contrived as an example of the problem. Not the real problem code. – ctrl-alt-delor Jul 24 '19 at 16:40
  • 1
    Why are arrays not an option? What does your data look like, then? – ilkkachu Jul 24 '19 at 16:51
  • 1
    Dear Stack Exchange community, It's okay that the answer to a question be "that's not possible". You don't have to downvote the question. Nearly every question I ask on here is for something that is not possible. That is because I am excellent at solving problems (or finding answers), and if I have to ask, it's probably impossible. If it were possible, I would have probably found the answer in the extensive research and trial and error I do before asking. – Bruno Bronosky Jul 30 '19 at 11:28
3

There are plenty of ways if you want to set the variable (read "$a$b", printf -v "$a$b" ..., declare "$a$b"=..., etc.).

If you want to read the value, it can be done if the final value is a number, using arithmetic expansion, because arithmetic expansion can be nested (but also see Security Implications of using unsanitized data in Shell Arithmetic evaluation):

$ a=a b=cd acd=10
$ echo $(($a$b))
10

In general, bash doesn't support nested substitution.

Of course, your toy example can be somewhat mimicked:

for prefix in alpha bravo charlie; do
    for suffix in date hash url path status; do
        declare -p "${prefix}_${suffix}"
    done
done

Or you can play around with eval:

eval "echo \"${prefix}_${suffix} is \${${prefix}_${suffix}}\""
| improve this answer | |
  • Yes, I was afraid that eval was the only alternative. I'm going to have to avoid that in this case. – Bruno Bronosky Jul 30 '19 at 11:34
2

You could use brace expansion to build the variable names:

for i in {alpha,bravo,charlie}_{date,hash,url,path,status}; do
  echo "$i is ${!i}"
done
| improve this answer | |
  • I'm aware of this kind of expansion and use it all the time. But I've never done a N dimensional use like this. This blew my mind. I'm going to retrofit this into a few projects. Thanks! – Bruno Bronosky Jul 24 '19 at 18:27
1

If using ksh93 instead, you could do:

data=(
  [alpha]=(
    [date]=1563980822
    [hash]=bfc1a9ad
    [url]=http://example.com/bfc1a9ad
    [path]=/build/alpha
    [status]=failure
  )
  [bravo]=(
    [date]=1563981822
    [hash]=f76025c5
    [url]=http://example.com/f76025c5
    [path]=/build/alpha2
    [status]=success
  )
  [charlie]=(
    [date]=1563982822
    [hash]=289f55fd
    [url]=http://example.com/289f55fd
    [path]=/build/charlie
    [status]=success
  )
)
for prefix in alpha bravo charlie; do
    for suffix in date hash url path status; do
        printf '%s\n' "$prefix, $suffix, ${data[$prefix][$suffix]}"
    done
done
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.