如何从 Perl 脚本捕获系统命令的 stdin 和 stdout?

发布于 2024-07-06 10:51:55 字数 276 浏览 9 评论 0 原文

在 Perl 脚本的中间,有一个我要执行的系统命令。 我有一个字符串,其中包含需要输入到 stdin 的数据(该命令仅接受来自 stdin 的输入),并且我需要捕获写入 stdout 的输出。 我研究了 Perl 中执行系统命令的各种方法,open 函数似乎就是我所需要的,只不过它看起来只能捕获 stdin 或 stdout,而不能同时捕获两者。

目前,我最好的解决方案似乎是使用 open,将 stdout 重定向到临时文件,并在命令完成后从文件中读取。 有更好的解决方案吗?

In the middle of a Perl script, there is a system command I want to execute. I have a string that contains the data that needs to be fed into stdin (the command only accepts input from stdin), and I need to capture the output written to stdout. I've looked at the various methods of executing system commands in Perl, and the open function seems to be what I need, except that it looks like I can only capture stdin or stdout, not both.

At the moment, it seems like my best solution is to use open, redirect stdout into a temporary file, and read from the file after the command finishes. Is there a better solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

执手闯天涯 2024-07-13 10:51:55

IPC::Open2/3 很好,但我发现通常我真正需要的是 IPC: :Run3,它以最小的复杂性很好地处理了简单的情况:

use IPC::Run3;    # Exports run3() by default

run3( \@cmd, \$in, \$out, \$err );

该文档将 IPC::Run3 与其他替代方案进行了比较。 即使您不决定使用它,也值得一读。

IPC::Open2/3 are fine, but I've found that usually all I really need is IPC::Run3, which handles the simple cases really well with minimal complexity:

use IPC::Run3;    # Exports run3() by default

run3( \@cmd, \$in, \$out, \$err );

The documentation compares IPC::Run3 to other alternatives. It's worth a read even if you don't decide to use it.

与君绝 2024-07-13 10:51:55

perlipc 文档 涵盖了许多实现此目的的方法,包括 IPC::Open2 和 IPC: :打开3。

The perlipc documentation covers many ways that you can do this, including IPC::Open2 and IPC::Open3.

心房的律动 2024-07-13 10:51:55

在脚本顶部的某个位置,包含一行

use IPC::Open2;

That will include the required module,通常默认情况下随大多数 Perl 发行版一起安装。 (如果没有,可以使用 CPAN 安装它。)然后,不使用 open,而是调用:

$pid = open2($cmd_out, $cmd_in, 'some cmd and args');

您可以通过将数据发送到 $cmd_in 来将数据发送到命令,然后通过从 $cmd_out 读取来读取命令的输出。

如果您还希望能够读取命令的 stderr 流,则可以使用 IPC::Open3 模块。

Somewhere at the top of your script, include the line

use IPC::Open2;

That will include the necessary module, usually installed with most Perl distributions by default. (If you don't have it, you could install it using CPAN.) Then, instead of open, call:

$pid = open2($cmd_out, $cmd_in, 'some cmd and args');

You can send data to your command by sending it to $cmd_in and then read your command's output by reading from $cmd_out.

If you also want to be able to read the command's stderr stream, you can use the IPC::Open3 module instead.

后知后觉 2024-07-13 10:51:55

IPC::Open3 可能会做你想做的事。 它可以捕获 STDERR 和 STDOUT。

http://metacpan.org/pod/IPC::Open3

IPC::Open3 would probably do what you want. It can capture STDERR and STDOUT.

http://metacpan.org/pod/IPC::Open3

浮萍、无处依 2024-07-13 10:51:55

我最近发现的一个非常简单的方法是 IPC::Filter 模块。 它可以让您非常直观地完成这项工作:

$output = filter $input, 'somecmd', '--with', 'various=args', '--etc';

请注意,如果您向它传递一个列表,它如何调用您的命令,而无需通过 shell。 它还可以合理地处理常见实用程序的错误。 (失败时,它死亡,使用 STDERR 中的文本作为错误消息;成功时,STDERR 被丢弃。)

当然,它不适合大量数据,因为它没有提供任何方法进行任何流处理; 此外,错误处理可能不够精细,无法满足您的需求。 但它使许多简单的情况变得非常非常简单。

A very easy way to do this that I recently found is the IPC::Filter module. It lets you do the job extremely intuitively:

$output = filter $input, 'somecmd', '--with', 'various=args', '--etc';

Note how it invokes your command without going through the shell if you pass it a list. It also does a reasonable job of handling errors for common utilities. (On failure, it dies, using the text from STDERR as its error message; on success, STDERR is just discarded.)

Of course, it’s not suitable for huge amounts of data since it provides no way of doing any streaming processing; also, the error handling might not be granular enough for your needs. But it makes the many simple cases really really simple.

微凉 2024-07-13 10:51:55

我想你想看看 IPC: :打开2

I think you want to take a look at IPC::Open2

当梦初醒 2024-07-13 10:51:55

有一个特殊的 perl 命令,

open2()

可以在以下位置找到更多信息: http://sunsite.ualberta.ca/Documentation/Misc/perl-5.6.1/lib/IPC/Open2.html

There is a special perl command for it

open2()

More info can be found on: http://sunsite.ualberta.ca/Documentation/Misc/perl-5.6.1/lib/IPC/Open2.html

幽蝶幻影 2024-07-13 10:51:55

如果您不想包含额外的软件包,您可以这样做,

open(TMP,">tmpfile");
print TMP  $tmpdata ;
open(RES,"$yourcommand|");
$res = "" ;
while(<RES>){
$res .= $_ ;
}

这与您的建议相反,但也应该可行。

If you do not want to include extra packages, you can just do

open(TMP,">tmpfile");
print TMP  $tmpdata ;
open(RES,"$yourcommand|");
$res = "" ;
while(<RES>){
$res .= $_ ;
}

which is the contrary of what you suggested, but should work also.

口干舌燥 2024-07-13 10:51:55

如果我只期望单行输出或想要将结果拆分为换行符以外的其他内容,我总是这样做:

my $result = qx( command args 2>&1 );  
my $rc=$?;  
# $rc >> 8 is the exit code of the called program.

if ($rc != 0 ) {  
    error();  
}  

如果要处理多行响应,请将结果作为数组获取:

my @lines = qx( command args 2>&1 );  

foreach ( my $line ) (@lines) {  
    if ( $line =~ /some pattern/ ) {  
        do_something();  
    }  
}  

I always do it this way if I'm only expecting a single line of output or want to split the result on something other than a newline:

my $result = qx( command args 2>&1 );  
my $rc=$?;  
# $rc >> 8 is the exit code of the called program.

if ($rc != 0 ) {  
    error();  
}  

If you want to deal with a multi-line response, get the result as an array:

my @lines = qx( command args 2>&1 );  

foreach ( my $line ) (@lines) {  
    if ( $line =~ /some pattern/ ) {  
        do_something();  
    }  
}  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文