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
  • Why not? Is it an outdated bash? If so, you probably should include that in the question. – muru Jul 24 '19 at 15:46
  • 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 Answers3

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}}\""
muru
  • 72,889
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
Freddy
  • 25,565
  • 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