2017-02-07 5 views
0

Если у меня есть простой Баш скрипт set_token.sh:Eval команда не работает в цикле

#!/bin/bash 

output='export AWS_ACCESS_KEY_ID="111" 
export AWS_SECRET_ACCESS_KEY="222" 
export AWS_SESSION_TOKEN="333"' 

echo "$output" | while read line; do eval $line; done 

Executed set_token.sh не был успешно установлен на 3 переменные среды. Однако, если я запускаю eval на каждой строке отдельно, он работает.

$ eval 'export AWS_ACCESS_KEY_ID="111"' 
$ eval 'export AWS_SECRET_ACCESS_KEY="222"' 
$ eval 'export AWS_SESSION_TOKEN="333"' 

Почему это так?

+5

Вы устанавливаете переменные в среде подоболочки, когда вы трубу; см. [BashFAQ 24] (http://mywiki.wooledge.org/BashFAQ/024). –

+0

@Tony Vu: Планируете ли вы рассказать нам о своем требовании? Ваша проблема решена или вы застряли? – Inian

+1

После того, как вы исправите [BashFAQ # 24] (http://mywiki.wooledge.org/BashFAQ/024), тогда выполнение вашего скрипта установит три переменные ... и выйдет, а новые назначенные переменные исчезнут со смертью оболочку, в которую они были установлены. 'export'ing variable изменяет среду * child * процессов, а не родительских процессов. –

ответ

3

Вы можете достичь желаемого результата без петли и без eval.

source <(echo "$output") 

<() конструкция представляет собой замену процесса. Он выполняет команду, найденную внутри, создает FIFO (специальный файл с первым входом, первым выходом) и затем преобразуется в фактический путь к файлу (указывающий на FIFO), который может читать source.

Конечно, вы также можете сохранить фактические назначения в файле, а не помещать их в переменную output.

source config_file 

source команда (или более стандартная форма .) считывает команды из файла и выполняет их в текущей оболочке, без запуска отдельного процесса или подоболочку, поэтому присвоения переменных в Sourced файлов работают. Полезно для конфигурационных файлов, но, конечно же, вы должны быть уверены, что никто не может помещать произвольные команды в эти файлы, поскольку это будет угрозой безопасности.

ВАЖНО

Если вы хотите поместить объявления в скрипте (set_token.sh в вашем случае), этот сценарий необходимо быть получены (т.е. выполняется с source или .), не выполняется с bash или позвонив по телефону он напрямую (если он является исполняемым).Любой метод, отличный от source или ., запустит дочерний процесс, и дочерний процесс не сможет назначить переменные, которые впоследствии будут видны родительскому процессу. Sourcing не создает отдельный процесс, поэтому задания будут работать. Ключевое слово export сделает присваивания видимыми только для дочерних процессов, они не могут сделать назначения видимыми для родителя.

+0

Спасибо, но это не сработало –

+2

@TonyVu Пожалуйста, см. ВАЖНУЮ секцию, которую я добавил к моему ответу, и я сильно подозреваю, почему она не сработала для вас (потому что сама техника работает, в этом нет никаких сомнений). – Fred

+1

Привет @Fred, используя источник или. работает. –

1

Не знаете, почему вы хотите использовать eval в этом случае. Почему бы не установить переменные более непосредственно, как это:

export AWS_ACCESS_KEY_ID="111" 
export AWS_SECRET_ACCESS_KEY="222" 
export AWS_SESSION_TOKEN="333" 

Ваш цикл выполняется в подкаталоге оболочке (из-за echo "$output" | ...), и поэтому ваши переменные не видны снаружи. Дело не в том, что eval не работает! Не волнуйтесь - это случается с большим количеством людей.

Если вы настойчивы об использовании петли и eval, вы могли бы использовать процесс замены < <(command):

while read line; do eval $line; done < <(printf "%s\n" "$output") 
+0

'++' для правильных путей, btw вложил ваш ответ в мой, чтобы подчеркнуть, что вы не используете 'eval' и рекомендуем альтернативные способы. – Inian

+0

Спасибо. В моем случае переменные генерируются динамически. Я просто использовал вывод здесь для простоты. Это, по-видимому, правильная причина, но замещение процесса по-прежнему не работает для меня. –

+0

@TonyVu: Что еще вы ищете? – Inian

0

Fred's helpful answer содержит жизнеспособное решение и хорошие указатели (и проблема с первоначальным подходом объясняется в Bash FAQ #24 - "I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates?").

Тем не менее, в вашем конкретном случае - если вы готовы принять на себя риск использования eval - вы можете применить его непосредственно к вашему многострочному строки:

#!/bin/bash 

output='export AWS_ACCESS_KEY_ID="111" 
export AWS_SECRET_ACCESS_KEY="222" 
export AWS_SESSION_TOKEN="333"' 

# This defines all 3 AWS_* environment variables. 
eval "$output" 

Чтобы подтвердить точку Фреда для переменных среды вступили в силу в тока оболочки, вы должны источник скрипт (используя встроенный . или его (эффективный) псевдоним source):

. ./set_token.sh