(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
が実際に入力を読み取る正しい方法である可能性があります(ただし、変数値に改行が含まれていない場合にのみ疑います)。入力形式が曖昧であるか、解析が複雑である可能性もあります。変数の値の1つに改行文字、二重引用符、またはバックスラッシュが含まれている場合にどうなるかを確認します。
入力を確実に変換する1つのポイントは、値を抽出するときです。
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
まず、変数の置換を二重引用符で囲む必要がありecho "${kv#*=}"
ます。それ以外の場合、シェルはワード分割とファイル名生成(つまり、グロビング)を実行します。2つ目echo
は、aで始まる一部の文字列-
はオプションとして扱われ、一部のシェルは引数に対してバックスラッシュ展開を実行するため、文字列を出力する信頼できる方法ではありません。文字列を印刷するための信頼できる移植可能な方法はprintf %s "${kv#*=}"
です。また、値が複数行にわたる場合、sedプログラムはそれぞれ個別に動作しますが、これは誤りです。これは修正可能ですが、シェルの文字列操作機能を使用する簡単な方法がありますval=${kv#*=}; val=${val#\"}; val=${val%\"}
。
入力がplain read
で正しく解析されると仮定すると、IFS
各行を分割する設定を利用して、入力を解析する簡単な方法を次に示します。
while read name value; do
value=${value#\"}; value=${value%\"}
export name="$value"
done <"$1"
key=${kv%%=*}
よりもkey=${kv%=*}
最短または最長の取り外し可能な部品です