( jw013 уже дал правильный ответ , но я хочу указать еще несколько вопросов.)
Правая часть конвейера работает в собственной оболочке в bash (как и большинство других оболочек, за исключением ATT ksh и zsh). Таким образом, вы устанавливаете переменные среды в подоболочке, которая выполняет цикл, но не в основном процессе оболочки.
Здесь есть простое решение, которое должно заменить бесполезное использование cat
перенаправления:
while read …; do …; done <"$1"
В общем, если вам нужно предварительно обработать ввод, поместите цикл и оставшуюся часть скрипта (по крайней мере, ту часть, которая нуждается в измененных переменных) внутри блока.
grep '^foo_' "$1" | {
while read …; do …; done
do_something
}
Обратите внимание, что, как правило, while read line; do …
не совсем перебирать строки ввода. См. Почему while IFS= read
используется так часто, а не IFS=; while read..
? для объяснения. Правильная идиома для перебора входных строк
while IFS= read -r line; do …
Здесь удаление начальных и конечных пробелов не имеет значения, так как не должно быть никаких заданных вами входных данных, но вам может потребоваться -r
избегать расширения с обратной косой чертой. Возможно, while read line
это действительно правильный способ чтения ваших входных данных (но я подозреваю, что только если значения переменных не содержат символов новой строки). Также возможно, что ваш формат ввода является неоднозначным или более сложным для анализа. Проверьте, что произойдет, если значение одной из переменных содержит символ новой строки, двойную кавычку или обратную косую черту.
Одна точка, в которой вы определенно искажаете ввод, - это когда вы извлекаете значение:
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
Во- первых, вы должны использовать двойные кавычки подстановки переменных: echo "${kv#*=}"
; в противном случае оболочка выполняет разбиение по словам и генерацию имени файла (то есть сглаживание) на нем. Во-вторых, echo
это не надежный способ печати строки, потому что некоторые строки, начинающиеся с a -
, обрабатываются как параметры, а некоторые оболочки выполняют расширение обратной косой черты для аргумента. Надежный и портативный способ печати строки printf %s "${kv#*=}"
. Кроме того, если значение занимает несколько строк, программа sed будет работать с каждой отдельно, что неправильно. Это поправимо, но есть более простой способ, который заключается в использовании манипуляции строки средства оболочечного: val=${kv#*=}; val=${val#\"}; val=${val%\"}
.
Предполагая, что ваш ввод правильно проанализирован с помощью простого read
, вот более простой способ его проанализировать, воспользовавшись IFS
настройкой для разделения каждой строки:
while read name value; do
value=${value#\"}; value=${value%\"}
export name="$value"
done <"$1"
key=${kv%%=*}
лучше, чемkey=${kv%=*}
потому, что %% и ## отличаются от% и # для того, является ли удаленная часть самая короткая или самая длинная съемная часть