2016-03-11 4 views
1

У меня есть небольшая проблема с переменной имя конкатенация или замена в BASH. Приведен:Имя переменной переменной массива BASH

#!/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 

Ожидаемый как результат был:

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

я получил:

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

Это только половина решения, потому что это только первый элемент копируется из каждого исходного массива а не полностью скопирован в рабочий массив $ Audio. В PHP я бы написал замену имени переменной просто:

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

К сожалению, я не могу использовать PHP для этого приложения. Конечно, это один из моих первых сценариев в BASH. Переключение на любое другое кодирование (например, многие простые переменные вместо нескольких массивов) не является вариантом. Я должен использовать эти пресеты. Итак, где моя вина, что случилось?

Greetings - Bert

+0

Элементы массива разделены пробелами, а не запятыми. – chepner

+0

Спасибо. Я чувствую, что это будет не последняя ошибка. – Bert

ответ

1

В версиях BASh 4.3+ можно использовать 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 делает NAME ссылку на переменную с именем его value. Таким образом, в коде выше Audio является ссылкой на значение, содержащееся в Audio1, Audio2, Audio3 и т.д.

+1

Спасибо, anubhava! Я думаю, это лучшее решение. Я прочитал много объяснений о манипуляции с именами переменных, но этот пункт «объявить» я перескакивал каждый раз. Казалось, это не так. – Bert

+0

'-n' делает' NAME' ссылкой на переменную с именем 'значение'. Поэтому в приведенном выше коде 'Audio' есть ссылка на значение, содержащееся в' $ Audio' – anubhava

+0

[Вот рабочая демонстрация] (http://ideone.com/N6TYRc) – anubhava

1

Без использования namerefs, вы можете сделать:

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 

выходы

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 

Я пропустил ваш желаемый результат. Вот он:

$ 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 
+0

Спасибо, Гленн тоже. Это не совсем желаемый результат, но для более позднего использования простых частей моих массивов я собираюсь напомнить ваше решение в глубине моего разума. – Bert

+1

Читайте об [переменной косвенности] (https://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion) в руководстве bash (пропустите пару абзацев) –

Смежные вопросы