4

次の例echoでは、パイプライン内の前のコマンドの終了コードに関係なく、ステートメントが実行されます。

asemenov@cpp-01-ubuntu:~$ 
asemenov@cpp-01-ubuntu:~$ false|echo 123
123
asemenov@cpp-01-ubuntu:~$ true|echo 123
123
asemenov@cpp-01-ubuntu:~$ 

前のコマンドのゼロecho終了コードでのみコマンドを実行したい、つまりこの動作を実現したい:

asemenov@cpp-01-ubuntu:~$ false|echo 123
asemenov@cpp-01-ubuntu:~$ 

bashで可能ですか?

より実用的な例を次に示します。

asemenov@cpp-01-ubuntu:~$ find SomeNotExistingDir|xargs ls -1
find: `SomeNotExistingDir': No such file or directory
..
..
files list from my current directory
..
..
asemenov@cpp-01-ubuntu:~$ 

xargs ls -1失敗した場合に実行する理由はありませfindん。

4

5 に答える 5

1

コマンド フローに関して、必要なことを実行する最も簡単な方法は、次のように論理 OR 演算子を使用することです。

[pierrep@DEVELOPMENT8 ~]: false || echo 123
123
[pierrep@DEVELOPMENT8 ~]: true || echo 123
[pierrep@DEVELOPMENT8 ~]:

これは、||演算子が遅延方式で評価されるため機能します。つまり、左側のステートメントが false または 1 に評価された場合にのみ、右側のステートメントが評価されます。

: 正常に実行されたコマンドは、成功すると終了ステータス 0 を返します。そうでない場合は 0 以外。あなたの例ではfind

[pierrep@DEVELOPMENT8 ~]: find somedir || echo 123
find: `somedir': No such file or directory
123
[pierrep@DEVELOPMENT8 ~]: find .profile || echo 123
.profile

を使用||すると、 の左側にあるコマンドからのいかなる種類の出力もリダイレクトされません||。成功した場合にのみコマンドを実行したい場合は、次のように、基本的な終了コード チェックを実行し、次のコマンドにフィードするために、スクリプト内の変数に 1 つのコマンドの出力を一時的に保存する必要があります。

$result=( $(find SomeNotExistingDir) )
$exit_code=$?
if [ $exit_code -eq 0 ]; then
    for path in ${result[@]}; do
        #do some stuff with the find results here...
        echo $path;
    done
fi

動作: find を実行すると、結果が$result配列に格納されます。$?最後の実行コマンドの終了コードを保持するため、ここではfindコマンドです。find見つかった場合はSomeNotExisitingDir、その結果をループし (複数のインスタンスが見つかった可能性があるため)、それらのパスを処理します。そうでなければ何もしません。ここでelseは、コマンドの実行中にエラーが発生したfind場合、またはファイル/ディレクトリが見つからなかった場合にトリガーされます。

于 2012-12-10T10:01:28.373 に答える
1

パイプラインのコンポーネントは、常に無条件かつ論理的に並行して実行されます。最初の (またはそれ以前の) プロセスが正常に完了した場合にのみ、パイプラインで 2 番目 (またはそれ以降) のプロセスを作成することはできません。

で示した特定のケースでfindは、少なくとも 2 つのオプションがあります。

find SomeNotExistingDir ... -exec ls -1 {} +

または、GNU の非常に便利な機能を使用できますxargs( POSIXにはありません)。

find SomeNotExistingDir ... | xargs -r ls -1

オプションは-rオプションと同等--no-run-if-emptyであり、それが何をするかをかなり正確に説明しています。GNUfindと GNUxargsを使用している場合は、拡張機能と を使用する必要があり-print0ます-0

find SomeNotExistingDir ... -print0 | xargs -r -0 ls -1

これにより、ファイル名に表示されるすべての文字が正しく処理されます。

于 2012-12-10T09:17:58.260 に答える
0

パイプの作成は完了を待たないため、パイプでそれを行うことはできませんcat | tr 'a-z' 'A-Z'。テスト ファイルと一時ファイルを使用したパイプのシミュレーション:

file1=$(mktemp)
file2=$(mktemp)
false > $file1 && (echo 123 > $file2) < $file1 && (prog3 > $file1) < $file2 && #.... 
rm $file1 $file2
于 2012-12-10T08:11:35.123 に答える
0

ポイントは、最初のコマンドが失敗すると、2 番目のコマンドの出力がなく、それを実行する理由がないということです。この動作の結果は予期しないものになります。

終了コードがゼロ以外のときに stdout に出力がない場合、この情報自体をデータのパイプに使用できます。終了コードを確認する必要はありません。(コース外の最適化部分を除く。)

例えば最適化部分を無視して正しさ部分だけ考えれば、

find SomeNotExistingDir|xargs ls -1

に変更できます

find SomeNotExistingDir| while read x; do ls -1 "$x"; done

while ループを除いて、その中のコマンドは実行されません。このアプローチの欠点は、ls の代わりに使用される awk/sed/head などのコマンドの一部の情報 (行番号など) が失われることです。さらに、xargs アプローチの場合、ls は 1 回ではなく N 回実行されます。

于 2012-12-10T08:28:24.910 に答える
0

あなたが与えた特定の例では、パイプにデータがあるかどうかを確認するだけで十分です。発生する問題は、入力が得られないため、引数なしxargsで呼び出し、デフォルトで現在のディレクトリの内容を出力することです。anishsane の解決策はほぼ十分ですが、出力の各行に対して呼び出すため、まったく同じではありません。ただし、次のことができます。lslslsxargs

find /bad/path | xargs sh -c 'test $# = 0 || exec ls -1 "$@"'

さて、このパイプラインは常に成功しますが、おそらくそれは望ましくありません (ただし、これはただの場合と同じ動作ですfind /bad/path | xargs ls -l)。パイプラインが失敗することを確認するには、次のようにします。

find /bad/path | xargs sh -c 'test $# = 0 && exit 1; exec ls -1 "$@"'

ただし、いくつかの懸念があります。 xargs多くの引数を指定してそのコマンドを非常に喜んで呼び出します (それがポイントです!) が、一部のシェルは xargs よりもはるかに少数の引数を処理するため、シェルが引数を切り詰める可能性は十分にあります。しかし、それはおそらく学術的な懸念です。

于 2012-12-11T00:03:34.977 に答える