( jw013 ha già dato una risposta corretta , ma voglio sottolineare qualche altro problema.)
Il lato destro di una pipeline viene eseguito nella propria subshell in bash (così come nella maggior parte delle altre shell, con l'eccezione ATT ksh e zsh). Quindi stai impostando le variabili di ambiente nella subshell che esegue il ciclo, ma non nel processo principale della shell.
Ecco una soluzione semplice che è quella di sostituire l'uso inutile di cat
un reindirizzamento:
while read …; do …; done <"$1"
In generale, se è necessario preelaborare l'input, inserire il ciclo e il resto dello script (almeno la parte che necessita delle variabili modificate) all'interno di un blocco.
grep '^foo_' "$1" | {
while read …; do …; done
do_something
}
Si noti che in generale, while read line; do …
non scorre completamente sulle righe di input. Vedi Perché viene while IFS= read
usato così spesso, invece di IFS=; while read..
? per una spiegazione. Il linguaggio corretto per iterare sulle righe di input è
while IFS= read -r line; do …
Qui, la rimozione di spazi bianchi iniziali e finali non ha importanza poiché non dovrebbe esserci alcun input di esempio, ma potrebbe essere necessario -r
evitare l'espansione della barra rovesciata. È possibile che while read line
sia in realtà un modo corretto di leggere il tuo input (ma sospetto solo se i valori delle variabili non contengono righe). È anche possibile che il tuo formato di input sia ambiguo o più complesso da analizzare. Controlla cosa succede se uno dei valori delle variabili contiene un carattere di nuova riga, una doppia virgoletta o una barra rovesciata.
Un punto in cui stai decisamente rovinando l'input è quando estrai il valore:
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
In primo luogo, è necessario utilizzare le virgolette attorno alla sostituzione di variabile: echo "${kv#*=}"
; in caso contrario la shell esegue la suddivisione delle parole e la generazione del nome del file (ovvero globbing) su di essa. In secondo luogo, echo
non è un modo affidabile per stampare una stringa, poiché alcune stringhe che iniziano con a -
sono trattate come opzioni e alcune shell eseguono l'espansione della barra rovesciata sull'argomento. Un modo affidabile e portatile per stampare una stringa è printf %s "${kv#*=}"
. Inoltre, se il valore si estende su più righe, il programma sed agirà su ciascuna separatamente, il che è errato. Questo è risolvibile, ma c'è un metodo più semplice, che è quello di utilizzare gli impianti di manipolazione delle stringhe della shell: val=${kv#*=}; val=${val#\"}; val=${val%\"}
.
Supponendo che il tuo input sia correttamente analizzato con un semplice read
, ecco un modo più semplice per analizzarlo, sfruttando l' IFS
impostazione per dividere ogni riga:
while read name value; do
value=${value#\"}; value=${value%\"}
export name="$value"
done <"$1"
key=${kv%%=*}
è meglio dikey=${kv%=*}
perché %% e ## differiscono da% e # per sapere se la parte rimossa è la parte rimovibile più corta o più lunga