Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Perl中的qx{}语句中将变量的内容作为STDIN进行管道传输?_Perl - Fatal编程技术网

如何在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);