我基本上想这样做:
$_ = "some content that need to be escaped &>|\"$\'`\s\\";
qx{echo $_ | foo}
这里有两个问题。首先,$_
的内容需要转义,因为它可以包含二进制数据。其次,调用echo
可能效率不高。
如何简单地将一些内容作为STDIN传递给Perl中的命令?
答案 0 :(得分:4)
以下假设@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 IPC::Run3 qw( run3 );
run3(\@cmd, \$_, \my $output);
use IPC::Run qw( run );
run(\@cmd, \$_, \my $output);
如果您不想捕获输出,可以使用以下任何一种方法:
use String::ShellQuote qw( shell_quote );
my $cmd1 = shell_quote('printf', '%s', $_);
my $cmd2 = shell_quote(@cmd);
system("$cmd1 | $cmd2");
system('/bin/sh', '-c', 'printf "%s" "$0" | "$@"', $_, @cmd);
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote(@cmd);
open(my $pipe, '|-', $cmd);
print($pipe $_);
close($pipe);
open(my $pipe, '|-', '/bin/sh', '-c', '"$@"', 'dummy', @cmd);
print($pipe $_);
close($pipe);
use IPC::Run3 qw( run3 );
run3(\@cmd, \$_);
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);
注意:
使用printf
的解决方案会对要传递给程序STDIN的数据大小施加限制。
使用printf
的解决方案无法将NUL传递给程序的STDIN。
使用IPC :: Run3和IPC :: Run的解决方案不涉及shell。这可以避免问题。
您应该使用IPC :: System :: Simple中的system
和capture
而不是内置system
和qx
来获取“免费”错误检查。
答案 1 :(得分:3)
这个答案是一种非常天真的方法。它容易陷入僵局。 不要使用它!
ikegami explains in a comment下面:
如果父级对附加到子级STDIN的管道写入足够多,并且子级在从STDIN读取之前输出到连接到其STDOUT的管道足够,则会出现死锁。 (在某些系统上,这可能只有4KB。)解决方案涉及使用select,threads等等。更好的解决方案是使用已经为您解决问题的工具(IPC :: Run3或IPC ::跑)。在大多数情况下,IPC :: Open2和IPC :: Open3太低级别无法使用
我将保留原始答案,但鼓励读者从其他答案中选择解决方案。
您可以使用IPC::Open2中的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
。
请注意,您不能对您显示的确切输入使用双引号""
,因为反斜杠的数量\
是错误的。
有关详细信息,请参阅perldoc open
和perlipc。
答案 2 :(得分:2)
我喜欢@simbabque提供的解决方案,因为它避免调用Shell。无论如何,为了进行比较,可以使用Bash echo
使用Bash(但避免Here string
)获得更短的解决方案:
$_ = q{some content that need to be escaped &>|\"$\'`\s\\};
$_ =~ s/'/'"'"'/g; # Bash needs single quotes to be escaped
system 'bash', '-c', "foo <<< '$_'";
并且,如果您需要捕获命令的输出:
use Capture::Tiny 'capture_stdout';
my $res = capture_stdout { system 'bash', '-c', "foo <<< '$_'" };