12

Perl では、system() または `` (バッククォート) を使用してシステム コマンドを実行できます。コマンドの出力を変数に取り込むこともできます。ただし、これによりバックグラウンドでのプログラムの実行が隠されるため、スクリプトを実行している人はそれを見ることができません。

通常、これは便利ですが、舞台裏で何が起こっているのかを確認したい場合があります。実行されたコマンドが端末に出力され、それらのプログラムの出力が端末に出力されるようにするにはどうすればよいですか? これは.bat「@echo on」と同等です。

4

6 に答える 6

19

これを行うデフォルトの方法はわかりませんが、サブルーチンを定義してそれを行うことができます:

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);

そして、それを実際に見てください:

pbook:~/foo rudd$ perl foo.pl ls
ls
file1   file2   foo.pl
于 2008-08-20T01:47:02.190 に答える
10

私が理解しているように、system() はコマンドの結果を出力しますが、割り当てはしません。例えば。

[daniel@tux /]$ perl -e '$ls = system("ls"); print "Result: $ls\n"'
bin   dev  home  lost+found  misc  net  proc  sbin     srv  System  tools  var
boot  etc  lib   media       mnt   opt  root  selinux  sys  tmp     usr
Result: 0

バッククォートはコマンドの出力をキャプチャし、出力しません:

[daniel@tux /]$ perl -e '$ls = `ls`; print "Result: $ls\n"'
Result: bin
boot
dev
etc
home
lib

等...

更新:コマンドの名前も出力したい場合は、Ruddのアプローチが良いsystem()と思います。統合のためにここで繰り返します。

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);
于 2008-08-20T01:30:36.597 に答える
5

結果を出力して返す更新された実行を次に示します。

sub execute {
  my $cmd = shift;
  print "$cmd\n";
  my $ret = `$cmd`;
  print $ret;
  return $ret;
}
于 2008-08-20T16:33:40.217 に答える
5

代わりに open を使用してください。その後、コマンドの出力をキャプチャできます。

open(LS,"|ls");
print LS;
于 2008-08-20T00:04:56.210 に答える
2

うーん、興味深いことに、さまざまな人がこのさまざまな方法で答えています。私にはmkのように見え、Daniel Foneはそれをコマンドの stdout を表示/操作したいと解釈しました (どちらのソリューションも stderr fwiw をキャプチャしません)。ラッドが近づいたと思います。Rudd の応答に加えることができる 1 つのひねりは、組み込みの system() コマンドを独自のバージョンで上書きすることです。これにより、彼の execute() コマンドを使用するために既存のコードを書き直す必要がなくなります。

Rudd の投稿から彼の execute() サブルーチンを使用すると、コードの先頭に次のようなものを含めることができます。

if ($DEBUG) {
   *{"CORE::GLOBAL::system"} = \&{"main::execute"};
}

それはうまくいくと思いますが、これはブードゥー教であり、このコードを書いてからしばらく経っていることを認めなければなりません。モジュールのロード時にローカル (呼び出し元の名前空間) またはグローバル レベルでシステム コールをインターセプトするために、私が何年も前に書いたコードを次に示します。

  # importing into either the calling or global namespace _must_ be
  # done from import().  Doing it elsewhere will not have desired results.
  delete($opts{handle_system});
  if ($do_system) {
    if ($do_system eq 'local') {
      *{"$callpkg\::system"} = \&{"$_package\::system"};
    } else {
      *{"CORE::GLOBAL::system"} = \&{"$_package\::system"};
    }
  }
于 2008-08-20T02:06:10.490 に答える
2

回答に記載されている他の方法と組み合わせる別の方法は、teeコマンドを使用することです。例えば:

open(F, "ls | tee /dev/tty |");
while (<F>) {
    print length($_), "\n";
}
close(F);

これにより、( の結果としてtee /dev/tty) 現在のディレクトリ内のファイルが出力され、読み取られた各ファイル名の長さも出力されます。

于 2008-08-20T06:33:49.673 に答える