Perl の system() は、実行中のコマンドをどのように出力できるのでしょうか?
質問
Perl では、system() または `` (バッククォート) を使用してシステム コマンドを実行できます。コマンドの出力を変数にキャプチャすることもできます。ただし、これによりプログラムの実行がバックグラウンドで非表示になり、スクリプトを実行している人には見えなくなります。
通常、これは便利ですが、舞台裏で何が起こっているのかを確認したい場合もあります。実行されたコマンドが端末に出力され、それらのプログラムの出力が端末に出力されるようにするにはどうすればよいでしょうか?これは .bat
「@echo on」と同等。
解決
私が理解しているように、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
等...
アップデート: system() されたコマンドの名前も出力したい場合は、次のように思います ラッドさんのアプローチは良いですね。統合のためにここで繰り返します。
sub execute {
my $cmd = shift;
print "$cmd\n";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd);
他のヒント
これを行うデフォルトの方法はわかりませんが、それを行うサブルーチンを定義できます。
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
代わりにオープンを使用してください。その後、コマンドの出力をキャプチャできます。
open(LS,"|ls");
print LS;
以下は、結果を出力して返す更新された実行です。
sub execute {
my $cmd = shift;
print "$cmd\n";
my $ret = `$cmd`;
print $ret;
return $ret;
}
うーん、これに対してさまざまな人がさまざまな方法で答えているのは興味深いですね。私には次のように見えます mk そして ダニエル・フォン コマンドの 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"};
}
}
回答で言及されている他のテクニックと組み合わせる別のテクニックは、 tee
指示。例えば:
open(F, "ls | tee /dev/tty |");
while (<F>) {
print length($_), "\n";
}
close(F);
これにより、現在のディレクトリ内のファイルが両方とも出力されます (結果として) tee /dev/tty
)、読み取った各ファイル名の長さも出力します。