1

I’ve got a little problem with the variable name concatenation oder replacement in BASH. Given is:

#!/bin/bash
Audio1=(0:ita, 96k, AAC, 2.0, s16le, 48000)   # audio stream definitions
Audio2=(1:rus, 128k, AAC, 2.0, s16le, 48000)  # for use in ffmpeg or
Audio3=(2:klg, 96k, AAC, 1.0, s16le, 48000)   # avconv
# and so on, now processing the audio streams
for ((i=1 ; i<=8 ; i++)) ; do
  Audio="Audio$i"
  Audio=${!Audio}
  if [ ${#Audio[0]} -gt 0 ] ; then
    # do the job with $Audio, here examplaryly:
    echo ${Audio[@]}
  fi
done

Expected as result was:

0:ita, 96k, AAC, 2.0, s16le, 48000
1:rus, 128k, AAC, 2.0, s16le, 48000
2:klg, 96k, AAC, 1.0, s16le, 48000

I got:

0:ita,
1:rus,
2:klg,

It’s only half the solution, because there is only the first element copied of each source array instead of been totally copied into the working array $Audio. In PHP I would write the variable name replacement simply by:

for ($i=1; $i<=8; $i++) {
  $Audio = ${'Audio'.$i};     // ← that’s all the magic in PHP ;-)
  if (isset($Audio[0])) {
    // blabla
  }
}

Unfortunatelly, I can’t use PHP for this application. Of course, this is one of my first scripts in BASH. Switching over to any other coding (e.g. many simple variables instead of few arrays) aren’t an option. I have to use these presets. So, where’s my fault, what’s going wrong?

Greetings - Bert

2
  • Array elements are separated by whitespace, not commas. Commented Mar 11, 2016 at 21:20
  • Thanks. I feel, that will be not the last mistake. Commented Mar 11, 2016 at 21:36

2 Answers 2

1

In BASH versions 4.3+ you can use declare -n:

for ((i=1 ; i<=3; i++)) ; do
   declare -n Audio="Audio$i"
   if [[ ${#Audio[@]} -gt 0 ]]; then
       echo "${Audio[@]}"
   fi
done

0:ita, 96k, AAC, 2.0, s16le, 48000
1:rus, 128k, AAC, 2.0, s16le, 48000
2:klg, 96k, AAC, 1.0, s16le, 48000

-n makes NAME a reference to the variable named by its value. So in above code Audio is a reference to the value contained in Audio1, Audio2, Audio3 etc.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, anubhava! I think, it’s the best solution. I read many explanations about the variable name manipulation, but this item "declare" I have jumped over everytime. It seemed not to be the right thing.
-n makes NAME a reference to the variable named by its value. So in above code Audio is a reference to the value contained in $Audio
Thanks @chepner, yes indeed it is 4.3+
@Bert, if you have the right bash version, declare -n is exactly what you want.
bash says:GNU bash, Version 4.3.30(1)-release-(i586-pc-linux-gnu)
1

Without using namerefs, you can do:

Audio1=(0:ita, 96k, AAC, 2.0, s16le, 48000)   # audio stream definitions
Audio2=(1:rus, 128k, AAC, 2.0, s16le, 48000)  # for use in ffmpeg or
Audio3=(2:klg, 96k, AAC, 1.0, s16le, 48000)   # avconv

for i in {1..3}; do
    aryvar="Audio${i}[@]"   # this is the special magic indirect varname
    for value in "${!aryvar}"; do printf "%d\t%s\n" $i "$value"; done
    # ...........^^^^^^^^^^^^ expands to elements of the array
done

outputs

1   0:ita,
1   96k,
1   AAC,
1   2.0,
1   s16le,
1   48000
2   1:rus,
2   128k,
2   AAC,
2   2.0,
2   s16le,
2   48000
3   2:klg,
3   96k,
3   AAC,
3   1.0,
3   s16le,
3   48000

I missed your desired output. Here it is:

$ for i in {1..3}; do
    aryvar="Audio${i}[*]"    # note the "*" not "@"
    echo "${!aryvar}"
done
0:ita, 96k, AAC, 2.0, s16le, 48000
1:rus, 128k, AAC, 2.0, s16le, 48000
2:klg, 96k, AAC, 1.0, s16le, 48000

2 Comments

Thank you, Glenn, too. It isn’t exactly the wanted output, but for later possibly using of simple parts of my arrays I’m going to remind your solution in the back of my mind.
Read about variable indirection in the bash manual (skip down a couple of paragraphs)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.