web-dev-qa-db-ja.com

Perl:システムコールが成功した後も、「ordie」コマンドはスクリプトを終了します

私は次の行を使用して、機能する簡単なシステムコールを作成しています。

system ("mkdir -p Purged") or die "Failed to mkdir." ;

スクリプトを実行するとシステムコールが実行され、Purgedというディレクトリが見つかりますが、エラーメッセージが出力され、スクリプトが終了します。私の構文の何が問題になっていますか?

13
user3481208

それは少し紛らわしいでしょうね。 --Leonardo Herrera on 池上さんの答え

はい、systemコマンドがPerlでtrueとfalseを反転し、次のような楽しいロジックを作成することは混乱を招きます。

if ( system qw($command) ) {
    die qq(Aw... If failed);
}
else {
    say qq(Hooray! It worked!);
}

しかし、systemコマンドがこれを行う理由は理解できます。 Unixでは、終了ステータスがゼロの場合はプログラムが機能したことを意味し、ゼロ以外のステータスではsystem呼び出しが失敗した理由を知ることができます。たぶんあなたが呼んでいたプログラムは存在しません。たぶん、プログラムは期待通りに機能したのでしょう。たとえば、grepが機能するが、一致する行がなかった場合、grep1の終了コードを返します。 grepが0、1、または1より大きい戻りコードを返す場合を区別することをお勧めします。 (はい、Perlプログラムでgrepへのシステムコールを使用するのはばかげていることを私は知っていますが、それは私が考えることができる最初の例です)。

偶然の混乱を防ぐために、systemの出力を直接テストする代わりに、systemコマンドの終了ステータスを保持する変数を作成します。

my $error = system qw($command);
if ($error) {
    die qq(Aw... It failed);
}
else {
    say qq(Hooray! It worked!);
}

これは完全に不要であり、Perlを使用する人は、systemがPerlのtrueおよびfalseの定義を逆にすることを知っておく必要があります。 、しかし、朝にコーヒーを飲んでいなかった場合、他の誰かのコードを調べているときに、コーヒーを見逃す可能性があります。この小さなステップを実行すると、プログラムが少し論理的に見えるようになります。

system のPerldocは、システムコマンドの出力をテストして、何が起こったかを正確に確認できるコードを提供します。 (エラーが発生した場合、またはシステム割り込み信号によってsystem呼び出しが強制終了された場合)。何が悪かったのかを理解するためにsystemの戻り値を調べる必要があるかどうかを知るのは良いことです。

10
David W.

systemは、呼び出すコマンドの終了ステータスを返します。シェルでは、ゼロ終了ステータスは成功を意味します。ロジックを逆にする必要があります。

0 == system qw(mkdir -p Purged) or die "Failed to create the dir\n";
18
choroba

systemは成功すると_0_を返すため、andではなくorが必要です。

参照:use autodie qw( system );

6
ikegami

言及されていないものを追加しますが、それに付属し、静かに物事を台無しにする可能性があります。

systemが 'zero-or-not'を返すと、コマンド自体がシェルまたはexecvpによって正常に実行されたかどうかがわかります。 0は、コマンドが実行に成功したことを意味しません

ゼロ以外の返品の場合、詳細については$?を解凍する必要があります。これを行う方法については、 system を参照してください。 1つは、コマンドの実際の終了コードは$? >> 8です。これは、実行されたプログラムがその終了時に通信するように設計されたものです。

全体として、あなたはの効果のために何かをしたいと思うかもしれません

sub run_system {
    my ($cmd, @other_agrs) = @_;             # may do more via @other_args

    my ($cmdref, $sys_ret) = (ref $cmd, 0);  # LIST or scalar invocation?
    if ($cmdref eq 'ARRAY') {
        $sys_ret = system(@$cmd);
    }
    elsif (not $cmdref) {
        $sys_ret = system($cmd);
    }
    else { Carp::carp "Invocation error, got $cmdref" }

    return 1 if $sys_ret == 0;

    # Still here? The rest is error handling.
    Carp::carp "Trouble with 'system($cmd)': $?";
    print "Got exit " . ($? >> 8) . " from $cmd\n";
    return 0;  # or die (but then design changes)
}

これは、コード内でsystem == 0 or do { ... };などとして実行できますが、この方法では、エラー処理をより簡単に改善できる小さなライブラリがあり、最終的にはモジュールに切り替えて外部コマンドなどを管理することにします。 、ユーザーレベルの機能であるため、成功するとtrueが返されることは理にかなっています(systemの設計は変更していません)。

さらに、この場合、mkdir -pは静かであることを意味し、場合によっては、それができないときに何も言わないことがあります。これはもちろん設計によるものですが、注意する必要があります。

2
zdim

ワンラインソリューション:

system("if printf '' > tmp.txt; then exit 1; else exit 0; fi ;") or die("unable to clobber tmp.txt");
0
Jacob Wegelin