在Perl中,您可以使用system()或``(反引号)执行系统命令。 您甚至可以将命令的输出捕获到变量中。 但是,这会将程序执行隐藏在后台,以便执行脚本的人看不到它。
通常,这很有用,但有时我想看看幕后发生了什么。 如何做到将执行的命令打印到终端,并将那些程序的输出打印到终端? 这相当于<@echo on"的.bat。
我不知道执行此操作的任何默认方式,但是您可以定义一个子例程来为您执行此操作:
1 2 3 4 5 6 7 8 9
| sub execute {
my $cmd = shift;
print"$cmd
";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd); |
然后看看它的作用:
1 2 3
| pbook:~/foo rudd$ perl foo.pl ls
ls
file1 file2 foo.pl |
据我了解,system()将打印命令的结果,但不分配它。例如。
1 2 3 4 5
| [daniel@tux /]$ perl -e '$ls = system("ls"); print"Result: $ls
"'
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 |
反引号将捕获命令的输出而不打印:
1 2 3 4 5 6 7 8
| [daniel@tux /]$ perl -e '$ls = `ls`; print"Result: $ls
"'
Result: bin
boot
dev
etc
home
lib |
等等...
更新:如果您还想打印被system()命名的命令的名称,我认为陆克文的方法很好。在此处重复进行合并:
1 2 3 4 5 6 7 8 9
| sub execute {
my $cmd = shift;
print"$cmd
";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd); |
请改用open。然后,您可以捕获命令的输出。
1 2
| open(LS,"|ls");
print LS; |
这是更新的执行,将打印结果并返回它们:
1 2 3 4 5 6 7 8
| sub execute {
my $cmd = shift;
print"$cmd
";
my $ret = `$cmd`;
print $ret;
return $ret;
} |
嗯,很有趣,不同的人如何回答这种不同的方式。在我看来,就像mk一样,Daniel Fone将其解释为希望查看/操纵命令的标准输出(他们的解决方案均未捕获stderr fwiw)。我认为陆克文走近了。您可以对Rudd的响应做出的一种改变是用您自己的版本覆盖内置的system()命令,这样您就不必重写现有代码即可使用他的execute()命令。
使用他在Rudd的帖子中的execute()子代码,您可以在代码顶部添加以下内容:
1 2 3
| if ($DEBUG) {
*{"CORE::GLOBAL::system"} = \&{"main::execute"};
} |
我认为这行得通,但我不得不承认这是伏都教,距我编写此代码已经有一段时间了。这是我几年前编写的在模块加载时拦截本地(调用名称空间)或全局级别的系统调用的代码:
1 2 3 4 5 6 7 8 9 10
| # 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命令。例如:
1 2 3 4 5 6
| open(F,"ls | tee /dev/tty |");
while (<F>) {
print length($_),"
";
}
close(F); |
这将打印出当前目录中的文件(作为tee /dev/tty的结果),也将打印出每个读取的文件名的长度。