2012-08-28 17 views
6

ループ内でコマンドの行を読み込んでいるbashエイリアスを作成したいとします。出力を1行ずつ読み込むために、出力をreadにパイプする必要があると思います。しかし、私がそれをすると、エイリアスは存在しません。なぜwhileループ内で評価できないのですか?

私は私の.bashrcに次のものが含まれている場合:

for x in a1 a2; do 
    eval "alias $x='echo foo'" 
done 

echo -e "a3\na4" | while read x; do 
    eval "alias $x='echo foo'" 
done 

別名a1a2が存在するが、a3a4にはありません。これら2つのループの違いは何ですか?

+0

これは、whileループにパイプするときの非常に一般的な問題です。 [この回答](http://stackoverflow.com/questions/7612320/bash-weird-variable-scope-when-populating-array-with-results/7612420#7612420)、または[BashFAQ/024](http: //mywiki.wooledge.org/BashFAQ/024)を参照してください。 –

+5

また、ここでは 'eval'を使う必要はありません。 'alias $ x = 'echo foo''はエイリアスを定義する前に' $ x'を展開します。 – chepner

答えて

5

問題はパイプラインです。 a | b | cの形式のパイプラインでは、個々のコマンドa,b、およびcのそれぞれは、別のサブシェル[ ref]で実行されます。つまり、エイリアスを含む親の実行環境のコピーを受け取り、それを変更します(aliasを実行するなどして)独自のコピーを作成すると、親には影響しません[ ref]。あなたのケースでは

、あなたは、書面でこれを修正することができます:まだサブシェルでecho -e "a3\na4"を実行しますが、通常の/親実行環境でwhile -loopを実行します

while read x; do 
    eval "alias $x='echo foo'" 
done < <(echo -e "a3\na4") 

+0

前に '<(command)'構文を見たことがありません。 'command'の出力を指すファイル記述子を作成していますか? –

+0

@JeffKlukas:はい。これは "プロセス置換"と呼ばれ(http://www.gnu.org/software/bash/manual/bashref.html#Process-Substitutionを参照)、FIFOまたは '/ dev/fd'ファイルを使用します。ドキュメンテーションは、すべてのシステムで動作しないことを意味しますが、私が試したすべてのシステム(Cygwinを含む)で動作します。 – ruakh

6

パイプ内のwhileループはサブシェルで実行されます。あなたが行うことができます。

while read x; do 
    eval "alias $x='echo foo'" 
done << EOF 
a3 
a4 
EOF 
3

のbash 4.2以降では、サブシェルで実行からパイプの最後コマンドを維持するlastpipeオプションを設定することができます。これが機能するにはジョブ制御もオフ(set +m)でなければなりません。

shopt -s lastpipe 
set +m 
echo -e "a3\na4" | while read x; do 
    alias $x='echo foo' 
done 
+0

+1:お勧めします! – ruakh

関連する問題