2

私のPerlプログラムから、を使用してCで記述された別のコマンドを実行しようとしていsystemます。このコマンドには、文字列、浮動小数点数、2つの整数、浮動小数点数のペア、および別の文字列のいくつかの引数が必要です。私はこれを次のように実行しています

my $arg1="electron";
my $arg2=0.511;
# more definitions
system("./fermions $arg1 $arg2 $arg3 $arg4 " .
       "$arg5 $arg6 \"string\" > outfile.out");

$arg5いくつかの異なるフロート値になるように変更する必要があります。$arg5="1.0e5"forループでifステートメントを設定して実行し、値を文字列として変更することで、これを機能させました。これをフロートとしてできるようにしたいと思い、試してみました

system("./fermions $arg1 $arg2 $arg3 $arg4 " .
       "%e $arg6 \"string\" >outfile.out",
       $arg5);

しかし、それはうまくいきませんでした。別の選択肢はありますか、それとも私のifステートメントオプションだけですか?

4

2 に答える 2

6

sprintfprintf表記( "%e"など)を使用する場合は、Perl組み込みを使用する必要があります。そうしないと、リテラル引数として「%e」を渡すことになります。

于 2012-04-21T02:35:27.503 に答える
1

重要:コマンドが失敗したかどうかを判断するには、Perlの関数からの戻り値を常に確認する必要があります。system

以下のコードのように、Perlを使用sprintfしてfloat値をフォーマットします。はい、フォーマット指定子としてコマンドを使用することで逃げることができるかもしれませんが、コマンドが他の場所に迷子の%文字を持っている場合、驚くべき結果が得られる可能性があります。2つのステップを使用する方が安全です。

#! /usr/bin/env perl

use strict;
use warnings;

my @float_values = (1.0e5, 3.14159, 2.71828);

for my $f (@float_values) {
  my $arg5 = sprintf "%e", $f;

  system(qq[./fermions $arg5 "string" >> outfile.out]) == 0
    or warn "$0: fermions failed";
}

構文に慣れていない場合はqq[...]、二重引用符で囲まれた文字列のように機能しますが、区切り文字が異なるため、コマンドで二重引用符をエスケープする必要はありません。

活字の目的で他の引数を省略したことに注意してください。ただし、の値とともにそれらを補間することができます$arg5。もう1つの微妙な変更は、クラバリング>>ではなく追加用に切り替えることです。>

の代役を使用するfermions

#! /usr/bin/env perl
$" = "][";
warn "[@ARGV]\n";

一緒に実行されている2つのプログラムの出力は

[1.000000e +05][文字列]
[3.141590e +00][文字列]
[2.718280e +00][文字列]

用語に関して、システムコールとは、オペレーティングシステムからのサービスに対する低レベルの要求を指します。たとえば、、、、openなどcloseですunlink。Perlのシステム関数はシステムコールを利用しますが、2つの概念は異なります。

シェルがコマンドライン引数を混乱させないようにするために、perlipcの「SafePipeOpens」セクションで説明されている手法を使用しください。Perlsystemexec関数は、コマンド全体を含む単一の文字列ではなく、引数のリストが与えられるとシェルをバイパスします。

標準出力をリダイレクトしたいので、状況は少しトリッキーです。以下のコードは、子をフォークし、子STDOUTをに追加するように設定してから、子でoutfile.out実行fermionexecます。親は子が終了するのを待ち、失敗を報告します。

#! /usr/bin/env perl

use strict;
use warnings;

my @float_values = (1.0e5, 3.14159, 2.71828);

for my $f (@float_values) {
  my $arg5 = sprintf "%e", $f;

  my $pid = fork;
  if (defined $pid) {
    if ($pid == 0) {
      my $path = "outfile.out";
      open STDOUT, ">>", $path or die "$0: open $path: $!";
      exec "./fermions", $arg5, "string" or die "$0: exec: $!";
    }
    else {
      local $!;
      my $pid = waitpid $pid, 0;
      warn "$0: waitpid: $!" if $pid == -1 && $!;
      warn "$0: fermion exited " . ($? >> 8) if $?;
    }
  }
  else {
    die "$0: fork: $!";
  }
}
于 2012-04-21T13:13:05.617 に答える