结合重定向 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吗?我的意思是:我的代码还重定向STDOUTSTDERR,但是写入标量的代码不会“传递”给执行的进程。所以我担心在使用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 重定向到空白页面

Vue路由重定向、别名与导航守卫

将.htaccess重定向与apache别名结合起来

.htaccess 结合 301 重定向和 URI 重写

如何结合两个 Apache htaccess 重定向条件(http 到 https 和非 www 到 www)

Web安全相关:开放重定向(Open Redirection)