( jw013 já deu uma resposta correta , mas quero apontar mais alguns problemas.)
O lado direito de um pipeline é executado em seu próprio subshell no bash (assim como na maioria dos outros shells, as exceções são ATT ksh e zsh). Então, você está definindo as variáveis de ambiente no subshell que executa o loop, mas não no processo principal do shell.
Aqui há uma solução fácil, que é substituir o uso inútil de cat
um redirecionamento:
while read …; do …; done <"$1"
Em geral, se você precisar pré-processar a entrada, coloque o loop e o restante do script (pelo menos a parte que precisa das variáveis alteradas) dentro de um bloco.
grep '^foo_' "$1" | {
while read …; do …; done
do_something
}
Observe que, em geral, while read line; do …
não itera completamente sobre as linhas de entrada. Consulte Por que é while IFS= read
usado com tanta frequência, em vez de IFS=; while read..
? para uma explicação. O idioma correto para iterar nas linhas de entrada é
while IFS= read -r line; do …
Aqui, a remoção do espaço em branco à esquerda e à direita não importa, pois não deve haver nenhuma entrada de amostra, mas você pode precisar -r
evitar a expansão da barra invertida. É possível que while read line
seja de fato uma maneira correta de ler sua entrada (mas suspeito apenas se os valores das variáveis não contiverem novas linhas). Também é possível que seu formato de entrada seja ambíguo ou mais complexo para analisar. Verifique o que acontece se um dos valores das variáveis contiver um caractere de nova linha, aspas duplas ou barra invertida.
Um ponto em que você definitivamente está manipulando a entrada é quando extrai o valor:
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
Primeiro, você precisa de usar as aspas em torno da substituição de variáveis: echo "${kv#*=}"
; caso contrário, o shell executa a divisão de palavras e a geração de nome de arquivo (ou seja, globbing) nele. Segundo, echo
não é uma maneira confiável de imprimir uma string, porque algumas strings que começam com a -
são tratadas como opções e algumas shells executam expansão de barra invertida no argumento. Uma maneira confiável e portátil de imprimir uma string é printf %s "${kv#*=}"
. Além disso, se o valor abranger várias linhas, o programa sed atuará em cada um separadamente, o que está errado. Esta é corrigível, mas não há um método mais fácil, que é a utilização de instalações de manipulação de strings do shell: val=${kv#*=}; val=${val#\"}; val=${val%\"}
.
Supondo que sua entrada seja analisada corretamente com uma planície read
, aqui está uma maneira mais simples de analisá-la, aproveitando a IFS
configuração para dividir cada linha:
while read name value; do
value=${value#\"}; value=${value%\"}
export name="$value"
done <"$1"
key=${kv%%=*}
é melhor do quekey=${kv%=*}
porque %% e ## diferem de% e # para saber se a parte removida é a parte mais curta ou mais longa removível