2016-12-08 4 views
1

Я хочу заполнить ассоциативный массив в bash в несколько нетривиальной настройке. У меня есть конвейер команд для создания требуемого ввода для массива.bash: доступ к глобальным переменным из конвейера команд

Вот минимальный/игрушка пример:

declare -A mapping 
seq 10 | while read i; do 
    key="key_$i" 
    val="val_$i" 
    echo "mapping[$key]=$val" 
    mapping["${key}"]="${val}" 
done 

echo "${mapping["key_1"]}" 
echo "${mapping["key_2"]}" 

В этом примере mapping изменяется внутри while, но эти изменения не распространяются в глобальное пространство имен. Я думаю, это потому, что while работает внутри отдельной подоболочки, поэтому пространства имен расходятся.

Для того, чтобы избежать (что я предлагаю) проблему с подоболочками, я придумал следующее:

declare -A mapping 
while read i; do 
    key="key_$i" 
    val="val_$i" 
    echo "mapping[$key]=$val" 
    mapping["${key}"]="${val}" 
done < <(seq 10) 

echo "${mapping["key_1"]}" 
echo "${mapping["key_2"]}" 

Таким образом, часть поколения явно переходит в субоболочку, в то время как петля while налево на только верхний уровень. Строительные работы.

Мои вопросы: есть ли лучший способ достичь моей цели? И верно ли мое предложение о подоболочках? Если да, то почему bash использует подоболочку в первом случае, но не во втором?

РЕДАКТИРОВАТЬ: после немного больше копания, вопрос в основном является дубликатом this one. Хороший список опций для обработки этого вопроса можно найти на http://mywiki.wooledge.org/BashFAQ/024

+1

Ваше понимание подоболочку правильно, то выполняется команда трубы с обеих сторон в отдельных подоболочек, когда правая сторона (петля) завершает все изменения в этой субоболочке теряются. <<(команда), открывает команду в подоболочке, и цикл находится в основном, поэтому вы сохраняете изменения в цикле while. – 123

ответ

1

Не уверен, если это лучший способ, чем ваш второй фрагмент кода, а способ решить первый заключается в использовании суб оболочки { ... } сразу после трубы :

declare -A mapping 
seq 10 | { 
    while read i; do 
     key="key_$i" 
     val="val_$i" 
     echo "mapping[$key]=$val" 
     mapping["${key}"]="${val}" 
    done 

    echo "${mapping["key_1"]}" 
    echo "${mapping["key_2"]}" 
} 
+0

Интересно, хотя очевидно, что он может использоваться только в том случае, если использование 'mapping' может быть помещено внутри подоболочки. –