结合重定向 open() 到标量与 system()
Posted
技术标签:
【中文标题】结合重定向 open() 到标量与 system()【英文标题】:Combine redirecting open() to scalar with system() 【发布时间】:2021-03-03 09:16:17 【问题描述】:我编写了一个例程来“安全地”执行某些命令,并且我想使用open(STDOUT, '+<', \$stdout)
和类似的 STDERR 捕获字符串变量中的 STDOUT 和 STDERR。
我通过print "Test\n"
和print STDERR "Test2\n"
验证了重定向在例程中有效(我可以在$stdout
和$stderr
中找到输出)。
但是,当我通过system()
(Perl 的版本)运行命令时,输出仍然会发送到终端。
所以我想知道:打开一个标量值是否仅适用于 Perl 自己的 I/O?
如果是这样,我如何在不使用临时文件(有自己的问题)的情况下从system()
调用中捕获 STDOUT 和 STDERR?
(我已经看过https://***.com/a/109672/6607497)
首选的解决方案(如果存在的话)应该使用尽可能少的额外包,并且应该在 SLES 12 或 SLES 15 (openSUSE Leap 15.2) 上运行。 这些发行版仅提供一组有限的 Perl 模块。
【问题讨论】:
metacpan.org/pod/Capture::Tiny::Extended 可以做到。 我认为IPC::Run
也可以做到这一点。
试试perldoc IPC::Open3
@k-mx 你试过IPC::Open3
吗?我的意思是:我的代码还重定向STDOUT
和STDERR
,但是写入标量的代码不会“传递”给执行的进程。所以我担心在使用IPC::Open3
时也会发生同样的情况...
@Shawn 看来IPC::Run
不能分开STDOUT
和´STDERR`。
【参考方案1】:
您可以使用IPC::Run
轻松捕获输出。
写入标准输出和错误的测试脚本:
#!/bin/sh
# demo.sh
echo "To Standard Output"
echo "To Standard Error" >&2
以及运行它的 perl 脚本:
#!/usr/bin/env perl
use warnings;
use strict;
use IPC::Run qw/run/;
my ($out, $err);
run ["sh", "demo.sh"], \undef, \$out, \$err;
print "Standard output: ", $out;
print "Standard error: ", $err;
给出以下输出:
$ perl demo.pl
Standard output: To Standard Output
Standard error: To Standard Error
使用IPC::Run3
的替代方法(如果您不需要IPC::Run
的任何更高级的功能,这可能更可取):
#!/usr/bin/env perl
use warnings;
use strict;
use IPC::Run3;
my ($out, $err);
run3 ["sh", "demo.sh"], \undef, \$out, \$err;
print "Standard output: ", $out;
print "Standard error: ", $err;
【讨论】:
我试过IPC::Run3
执行('lsof', '-p', $$)
。它清楚地表明它也在使用(删除的)临时文件。所以实际上所有围绕问题的“魔法包装器”只是透明地重定向到文件和从文件中重定向。
@U. Windl, IPC::Run 使用管道。重新“只是透明地重定向到文件和从文件中重定向”,嗯,是的。由于三个原因,子进程无法在另一个进程中写入 Perl 标量:1)它不知道 Perl 标量是什么,2)如果它知道什么是标量,它将无法同步对标量的访问是,并且 3)它不能写入另一个进程的内存空间。可能应该首先提到一个:)
@ikegami "named 管道" 我猜。无论如何,在了解了所有这些之后,我决定编写自己的“临时文件临时重定向代码”,因为没有 Perl 魔术可以将写入文件描述符重定向到标量。我猜想写入一些共享的 POSIX 内存,然后将 SHM 内存映射到标量可能会有所帮助。所以我接受这个答案,因为它似乎是唯一的出路,即使不是最初想要的方式。
@U. Windl,不,IPC::Run 不使用命名管道(在 Linux 上)。只是普通的旧管道(2)管道。
@U. Windl,Re "因为没有 Perl 魔法",正确,sh
没有“Perl 魔法”允许它写入其他进程的地址空间。以上是关于结合重定向 open() 到标量与 system()的主要内容,如果未能解决你的问题,请参考以下文章
Codeigniter:form_open 重定向到空白页面