シェルコマンドを実行するために呼び出しを実行するPerlスクリプトがあり、複数のsystem()
コマンドを実行してコマンド間でデータを転送したいと思います。 (Perlから)次のようになります:
system("command1 | command2");
Perl のsystem()
目的は/bin/sh
Ubuntu Server システムで実行されるため、/bin/sh
他のdash
多くのシェルと同様に、ダッシュのパイプ出口値は右端のコマンドの出口値です。これは、次の内容が0
(成功的に)返されることを意味します。
system("false | true")
/bin/sh
私が使用していたシステムは、次のオプションを追加することで簡単に修正bash
できました。pipefail
system("set -o pipefail; false | true");
実際、これは私のローカルArchシステムで期待どおりに機能し、/bin/sh
そのポイントは次のとおりですbash
。
$ perl -le '$status = system("false | true"); print $status>>8'
0
$ perl -le '$status = system("set -o pipefail; false | true"); print $status>>8'
1
(はい、これが奇妙に見えることを知っていますが、Perlがわからない場合は、私の言葉を信じてください。実際の終了ステータスを取得するには8を移動する必要があります。)
ただし、実行される予定のマシンには次のものがあるため、dash
同じ操作が失敗します。
$ perl -le '$status = system("set -o pipefail; false | true"); print $status>>8'
sh: 1: set: Illegal option -o pipefail
2
set -e
また、ソリューションは以下を使用していません。
$ perl -le '$status = system("set -e; false | true"); print $status>>8'
0
パイプを使用しない、モジュールを使用するなど、いくつかのPerlの解決策を考えることができますが、ダッシュからIPC::System::Simple
直接これを行うより簡単な方法があるかもしれません。
dash
もしそうなら、パイプライン命令セットの終了状態が0
(成功)でなければならないことを知っているいくつかのトリック、トリック、またはオプションがありますか?みんなコマンドは有効であり、?のように失敗した場合はset -o pipefail
ゼロではありません。bash
ベストアンサー1
Dashでこれを行う方法はわかりませんが、/bin/sh
完全にバイパスすることはできます。
Perlは、system()
プログラマが何をしたいかを推測しようとします。引数がsh -c
1つだけで、その引数にシェルメタ文字が含まれている場合にのみ使用します。それ以外の場合は、指定されたコマンドを直接実行し、正確な引数を指定できます(「間接オブジェクト」を介して渡されるシェルまたはargv[0]
シェル$0
内のコマンド名を含む)。
パラメータ処理はパラメータ数によって異なります。 LISTに複数の引数がある場合、またはLISTが複数の値を持つ配列の場合、リストの最初の要素によって提供されるプログラムは、リストの残りの要素が提供する引数を使用して開始されます。
スカラー引数が1つしかない場合は、引数にシェルメタ文字が含まれていることを確認します。そうであれば、構文解析のために引数全体がシステムのコマンドシェルに渡されます(これは
/bin/sh -c
Unixプラットフォームではありますが、他のプラットフォームでは異なります)。
これら2つは同じexecve()
呼び出しを行います。
system{"/bin/sh"} ("sh", "-c", 'false |true; echo $?')
system('false |true; echo $?')
つまり、以下のようにこれですstrace
。
execve("/bin/sh", ["sh", "-c", "false |true; echo $?"], [/* 39 vars */]) = 0
(似ていますがforをsystem("sh", "-c", '...')
探して、単に代わりに実行されたシェルから渡されるという点で少し異なります。大きな違いはありません。)$PATH
sh
system("/bin/sh", "-c", '...')
/bin/sh
argv[0]
sh
したがって、Perlで実行できます。
system("bash", "-o", "pipefail", "-c", 'false |true; echo $?');
# or a bit shorter
system(qw/bash -o pipefail -c/, 'false |true; echo $?');
往復は避けsh
、そしてBashコマンドラインへの関連付けの二重引用符。