Perl的反引号,系统和exec有什么区别?


237

有人可以帮帮我吗?在Perl中,有什么区别:

exec "command";

system("command");

print `command`;

还有其他方法可以运行shell命令吗?


8
几乎是stackoverflow.com/questions/797127/…的完全相同的副本,除了这个拥有exec和另一个拥有管道。
迈克尔·迈尔斯

Answers:


268

执行

执行命令永不返回。就像一个return函数中语句。

如果找不到该命令,则exec返回false。它永远不会返回true,因为如果找到该命令,它将根本不会返回。也有在没有返回点STDOUTSTDERR或命令的退出状态。您可以在中找到有关它的文档 perlfunc,因为它是一个函数。

系统

执行命令,命令完成后继续执行Perl脚本。

返回值是命令的退出状态。您可以在中找到有关它的文档 perlfunc

反引号

例如system执行命令,并且在命令完成后继续执行您的perl脚本。

与命令system的返回值相反STDOUTqx//等同于反引号。您可以在中找到有关此文档的文档perlop,因为与systemexec它是一个运算符。


其他方法

上面缺少的是一种异步执行命令的方法。这意味着您的perl脚本和命令将同时运行。这可以通过完成open。它允许您阅读STDOUT/STDERR写入STDIN命令。但是,它取决于平台。

还有几个模块可以简化此任务。有IPC::Open2IPC::Open3IPC::Run,以及 Win32::Process::Create您是否在Windows上。


1
我认为您的意思是s / perlcunc / perlfunc / ... ...此外,perlipc文档还涉及到有关打开管道的深入知识。
短暂

7
perlcunc,也许这将是我的新昵称;-)
路德维希·

8
根据记录,反引号和qx []也填充$?。(操作系统返回值)。
jjohn

167

总的来说,我使用systemopenIPC::Open2,或IPC::Open3取决于我想做的事情。该qx//操作虽然简单,太在其功能限制到快的黑客是非常有用的外面。我发现open要方便得多。

system:运行命令并等待其返回

使用system时要运行的命令,不关心它的输出,并且不希望Perl脚本做任何事情,直到命令完成。

#doesn't spawn a shell, arguments are passed as they are
system("command", "arg1", "arg2", "arg3");

要么

#spawns a shell, arguments are interpreted by the shell, use only if you
#want the shell to do globbing (e.g. *.txt) for you or you want to redirect
#output
system("command arg1 arg2 arg3");

qx//或``:运行命令并捕获其STDOUT

使用qx//时要运行一个命令,捕捉它写到标准输出,并且不希望Perl脚本做任何事情,直到命令完成。

#arguments are always processed by the shell

#in list context it returns the output as a list of lines
my @lines = qx/command arg1 arg2 arg3/;

#in scalar context it returns the output as one string
my $output = qx/command arg1 arg2 arg3/;

exec:用另一个进程替换当前进程。

使用exec连同fork当你想运行一个命令,不关心它的输出,并且不希望等待它返回。 system真的只是

sub my_system {
    die "could not fork\n" unless defined(my $pid = fork);
    return waitpid $pid, 0 if $pid; #parent waits for child
    exec @_; #replace child with new process
}

您可能还需要阅读waitpidperlipc手册。

open:运行一个进程并为其STDIN或STDERR创建管道

使用open时要将数据写入过程的STDIN或从一个进程的标准输出读取数据(但不能同时在同一时间)。

#read from a gzip file as if it were a normal file
open my $read_fh, "-|", "gzip", "-d", $filename
    or die "could not open $filename: $!";

#write to a gzip compressed file as if were a normal file
open my $write_fh, "|-", "gzip", $filename
    or die "could not open $filename: $!";

IPC :: Open2:运行一个进程并创建一个到STDIN和STDOUT的管道

使用IPC::Open2时需要读取和写入到一个进程的标准输入和标准输出。

use IPC::Open2;

open2 my $out, my $in, "/usr/bin/bc"
    or die "could not run bc";

print $in "5+6\n";

my $answer = <$out>;

IPC :: Open3:运行进程并创建到STDIN,STDOUT和STDERR的管道

使用IPC::Open3时您需要捕获过程的所有三个标准的文件句柄。我会写一个示例,但是它的工作方式与IPC :: Open2的工作原理基本相同,但是参数和第三个文件句柄的顺序略有不同。


非常翔实和最新的答案。感谢@ chas-owens
Jassi

IPC :: Open3对于大多数用途来说太低级了。IPC :: Run3和IPC :: Run通常更合适。
ikegami

17

首先让我引用这些手册:

perldoc exec()

exec函数执行系统命令,并且永不返回 - 如果要返回,请使用system而不是exec

perldoc system()

与exec LIST完全相同,只是先完成一个派生,并且父进程等待子进程完成。

execsystem相比,反引号不会给您返回值,而是给您收集的STDOUT。

perldoc`String`

一个(可能)被插值然后作为/ bin / sh或其等效项的系统命令执行的字符串。Shell通配符,管道和重定向将受到尊重。返回命令收集的标准输出 ; 标准错误不受影响。


备择方案:

在更复杂的情况下,如果要获取STDOUT,STDERR或返回代码,则可以使用IPC :: Open2IPC :: Open3等众所周知的标准模块。

例:

use IPC::Open2;
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some', 'cmd', 'and', 'args');
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

最后,从CPAN 运行IPC :: Run也值得一看...


3
这是一个粗鲁的反应。您应该尽量避免发怒。
Shane C. Mason

1
我认为他只是参考了RTFM:P
v3。

其实并不意味着无礼;)还是删除了f字,以避免任何误会……
Benedikt Waldvogel 09年

2
我当然不认为这是无礼的。也许是Brusque,但这不是一个高度智能的问题,需要深思熟虑的答案。
ephemient

11

Perl的反引号(`system,和之间有什么区别exec

exec -> exec "command"; ,
system -> system("command"); and 
backticks -> print `command`;

exec

exec执行命令,从不恢复Perl脚本。对于脚本来说,就像return对函数的声明一样。

如果找不到该命令,则exec返回false。它永远不会返回true,因为如果找到该命令,它将根本不会返回。也有在没有返回点STDOUTSTDERR或命令的退出状态。您可以在perlfunc中找到有关它的文档,因为它是一个函数。

例如:

#!/usr/bin/perl
print "Need to start exec command";
my $data2 = exec('ls');
print "Now END exec command";
print "Hello $data2\n\n";

在上面的代码中,有三个print语句,但是由于exec离开了脚本,因此仅执行第一个print语句。另外,exec命令输出未分配给任何变量。

在这里,只有您只获得第一条print语句的输出和ls标准输出执行命令。

system

system执行命令,命令完成后将恢复您的Perl脚本。返回值是命令的退出状态。您可以在perlfunc中找到有关它的文档。

例如:

#!/usr/bin/perl
print "Need to start system command";
my $data2 = system('ls');
print "Now END system command";
print "Hello $data2\n\n";

在上面的代码中,有三个print语句。在system命令后恢复脚本时,将执行所有三个打印语句。

另外,运行的结果system 分配给data2,但分配的值是0(从退出代码ls)。

在这里,您将获得第一个print语句的输出,然后是ls命令的输出,然后是print标准输出中最后两个语句的输出。

反引号(`

像一样system,将命令括在反引号中会执行该命令,并在命令完成后恢复您的Perl脚本。与相比system,返回值是STDOUT命令的。qx//等同于反引号。您可以在perlop中找到有关它的文档,因为与system和不同exec,它是一个运算符。

例如:

#!/usr/bin/perl
print "Need to start backticks command";
my $data2 = `ls`;
print "Now END system command";
print "Hello $data2\n\n";

在上面的代码中,有三个print语句,所有三个语句都正在执行。的输出ls不会直接进入标准输出,而是分配给变量data2,然后由最终的print语句打印。


举例最好的解释。非常感谢。
Arslan Anwar

2

“ exec”和“ system”之间的区别在于,exec用“ command”替换您当前的程序,并且从不返回您的程序。另一方面,系统分叉并运行“命令”,并在完成运行后返回“命令”的退出状态。反向标记运行“命令”,然后返回代表其标准输出的字符串(无论它会打印到屏幕上的什么)

您还可以使用popen来运行Shell命令,我认为这里有一个Shell模块-“ use shell”使您可以透明地访问典型的Shell命令。

希望能为您澄清。


也许您是说use Shell;search.cpan.org/dist/Shell/Shell.pm)?我认为它没有被广泛安装,也不适用于这个问题……
ephemient

1
他的问题的最后一部分是“还有其他运行Shell命令的方式”-Shell是另一种运行Shell命令的方式。
Shane C. Mason

2
docs特别声明“此软件包是作为一个演示案例提供的,它说明了Perl的一些功能。不应将其用于生产程序。尽管它确实提供了用于获取任意命令的标准输出的简单接口,但可能会更好实现您所需的方式。”
Chas。欧文斯(Owens)

2
再次,它回答了他的“还有其他方法”的问题
Shane C. Mason

错误的,不受支持的方法不应在没有警告的情况下被告知是错误和不受支持的。
Chas。欧文斯2009年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.