シェルスクリプトの予期しない動作

シェルスクリプトの予期しない動作

2つのスクリプトがあります。

foo.sh:

#!/bin/bash
echo -e "one\ntwo" |
while read line; do
    cat not-existing
    echo hello $line
done

バー.sh:

#!/bin/bash
echo -e "one\ntwo" |
while read line; do
    ssh user@machine 'cat not-existing' # Here is the only difference
    echo hello $line
done

今私はそれらを実行します

$ ./foo.sh 
cat: not-existing: No such file or directory
hello one
cat: not-existing: No such file or directory
hello two

$ ./bar.sh 
cat: not-existing: No such file or directory
hello one

の出力bar.sh。これら2つのスクリプトが同じであることを願っています。

foo.shの出力がなぜbar.sh違うのですか?これはバグか機能ですか?


ノート

以下は期待どおりに機能します。つまり、出力は次のようになりますfoo.sh

#!/bin/bash
for line in `echo -e "one\ntwo"`; do
    ssh user@machine 'cat not-existing'
    echo hello $line
done

なぜ?

ベストアンサー1

ではbar.sh消費さtwoれますssh。最後の例では、echoループを開始する前に from の出力全体が使用されます。for

sshstdinでデータを食べないようにするには、を使用します。これにより、ループのstdinではなくwithのstdinがssh -nリンクされます。ssh/dev/nullwhile

これにより、期待どおりに機能します。

#!/bin/bash
echo -e "one\ntwo" |
while read line; do
    ssh -n user@machine 'cat not-existing' # Here is the only difference
    echo hello $line
done

書いたら

#!/bin/bash
echo -e "one\ntwo" |
while read line; do
    ssh user@machine 'cat'
    echo hello $line
done

その後、リモートシステムの出力は標準入力が渡され、ループから得られるためcat出力されます。入力の最初の行が消費されたため、代わりに印刷されます。twosshechotwooneread

おすすめ記事