如何在Perl中的qx{}语句中将变量的内容作为STDIN进行管道传输?
我基本上想这样做:如何在Perl中的qx{}语句中将变量的内容作为STDIN进行管道传输?,perl,Perl,我基本上想这样做: $_ = "some content that need to be escaped &>|\"$\'`\s\\"; qx{echo $_ | foo} 这里有两个问题。首先,需要转义$的内容,因为它可以包含二进制数据。其次,调用echo的效率可能稍低 我如何简单地将一些内容作为STDIN传输到Perl中的命令?这是一种非常幼稚的方法。很容易陷入僵局。不要用它 下: 如果父级向连接到子级STDIN的管道写入的数据足够多,并且如果子级在读取其STDIN之前向连接
$_ = "some content that need to be escaped &>|\"$\'`\s\\";
qx{echo $_ | foo}
这里有两个问题。首先,需要转义$的内容,因为它可以包含二进制数据。其次,调用echo的效率可能稍低
我如何简单地将一些内容作为STDIN传输到Perl中的命令?这是一种非常幼稚的方法。很容易陷入僵局。不要用它 下:
如果父级向连接到子级STDIN的管道写入的数据足够多,并且如果子级在读取其STDIN之前向连接到其STDOUT的管道输出的数据足够多,则将出现死锁。在某些系统上,这可能只有4KB。解决方案包括使用select、threads等。更好的解决方案是使用已经为您解决了问题的工具IPC::Run3或IPC::Run。IPC::Open2和IPC::Open3的级别太低,在大多数情况下都没有用处 我将保留原始答案,但鼓励读者从其他答案中选择解决方案 您可以使用open2从读取和写入同一进程 现在你不必担心逃避任何事情
use IPC::Open2;
use FileHandle;
my $writer = FileHandle->new;
my $reader = FileHandle->new;
my $pid = open2( $reader, $writer, 'wc -c' );
# write to the pipe
print $writer 'some content that need to be escaped &>|\"$\'`\s\\';
# tell it you're done
$writer->close;
# read the out of the pipe
my $line = <$reader>;
print $line;
这将打印48
请注意,不能对显示的确切输入使用双引号,因为反斜杠\的数量是错误的
有关更多信息,请参阅和。我喜欢@simbabque提供的解决方案,因为它避免调用Shell。无论如何,为了进行比较,可以使用Bash获得较短的解决方案,但使用Bash-Here字符串可以避免echo: 并且,如果需要捕获命令的输出:
use Capture::Tiny 'capture_stdout';
my $res = capture_stdout { system 'bash', '-c', "foo <<< '$_'" };
以下假设@cmd包含程序及其参数(如果有)
my @cmd = ('foo');
如果要捕获输出,可以使用以下任一选项:
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
my $output = qx{$cmd1 | $cmd2};
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2");
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2 >/dev/null");
如果不想捕获输出,可以使用以下任一方法:
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
my $output = qx{$cmd1 | $cmd2};
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2");
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2 >/dev/null");
如果您不想捕获输出,但也不想看到输出,则可以使用以下任一选项:
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
my $output = qx{$cmd1 | $cmd2};
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2");
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2 >/dev/null");
注:
使用printf的解决方案将对传递到程序STDIN的数据大小施加限制
使用printf的解决方案无法将NUL传递给程序的STDIN
提供的使用IPC::Run3和IPC::Run的解决方案不涉及shell。这避免了问题
您可能应该使用IPC::system::Simple中的system和capture,而不是内置的system和qx来获得免费的错误检查
是否要读取foo的输出?是并将其置于$\u,以便使用foo更改$\u的内容。这是一个单行程序吗?是的,它看起来像一个单行程序,但我想在Perl脚本中这样做。在对内容执行其他操作之前,我通过一些过滤器处理一些文件。类似$echo foobar | perl-pe's/f/ff/'| wc-c | perl-pe'$*=2'这样您就不必关心所有的转义。很好,但我更喜欢只使用核心模块。目前我使用File::Temp,但我不喜欢它it@nowox根据我的corelist,IPC::Open2和FileHandle都是第一次使用Perl5发布的。我相信这意味着从Perl5的初始版本开始。没有比这更多的核心模块了顺便说一句,5.6.1中附带了File::Temp。如果父级对附加到子级STDIN的管道写入足够多,并且如果子级在读取其STDIN之前向附加到其STDOUT的管道输出足够多,则将出现死锁。在某些系统上,这可能只有4KB。解决方案包括使用select、threads等。更好的解决方案是使用已经为您解决了问题的工具IPC::Run3或IPC::Run。IPC::Open2和IPC::Open3的级别太低,在大多数情况下都没有用处。如果不想捕获输出,请使用Open2'>&STDOUT',$writer。。。我们将避免这个问题。但是,您可以简单地使用openmy$writer,“|-”,我喜欢IPC::Run解决方案。看起来很简单!第一种解决方案是使用printf而不是echo,使用printf而不是echo有什么好处?@Håkon Hægland,很难正确地将任意值传递给echo,因为它们可以被解释为选项。此外,echo Recognite\Escape的某些版本需要进一步依赖于系统的转义。
use IPC::Run qw( run );
run(\@cmd, \$_);
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2 >/dev/null");
system('/bin/sh', '-c', 'printf "%s" "$0" | "$@" >/dev/null', $_, @cmd);
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote(@cmd);
open(my $pipe, '|-', "$cmd >/dev/null");
print($pipe $_);
close($pipe);
open(my $pipe, '|-', '/bin/sh', '-c', '"$@" >/dev/null', 'dummy', @cmd);
print($pipe $_);
close($pipe);
use IPC::Run3 qw( run3 );
run3(\@cmd, \$_, \undef);
use IPC::Run qw( run );
run(\@cmd, \$_, \undef);