我正在编写一个模仿gcc的perl脚本。我的脚本需要从gcc处理一些stdout。处理的部分已经完成,但我无法使简单的部分工作:如何将所有命令行参数转发到下一个进程(在我的情况下为gcc)。发送到gcc的命令行往往很长,并且可能包含许多转义序列,我现在不想通过转义来玩那个游戏,我知道在复杂的情况下在Windows上正确使用它是很棘手的。
基本上,
gcc.pl一些crazies\ t\\ "command line\""
并且gcc.pl必须将相同的命令行转发到真正的gcc.exe(我使用windows)。
我这样做:open("gcc.exe $cmdline 2>&1 |")
这样来自gcc的stderr被送到stdout而我的perl脚本处理stdout。问题是我无法在任何地方找到如何构建$cmdline
。
答案 0 :(得分:2)
我会使用AnyEvent::Subprocess:
use AnyEvent::Subprocess;
my $process_line = sub { say "got line: $_[0]" };
my $gcc = AnyEvent::Subprocess->new(
code => ['gcc.exe', @ARGV],
delegates => [ 'CompletionCondvar', 'StandardHandles', {
MonitorHandle => {
handle => 'stdout',
callback => $process_line,
}}, {
MonitorHandle => {
handle => 'stderr',
callback => $process_line,
}},
],
);
my $running = $gcc->run;
my $done = $running->recv;
$done->is_success or die "OH NOES";
say "it worked";
MonitorHandle委托的工作方式与重定向相同,只是您可以选择为每个stdout和stderr使用单独的过滤器。 “code”arg是一个表示要运行的命令的arrayref。
答案 1 :(得分:2)
"Safe Pipe Opens"描述了如何获取另一个命令的输出,而不必担心shell将如何解析它。该技术通常用于安全地处理不受信任的输入,但它也使您免于正确转义所有参数的容易出错的任务。
因为它会回避shell,你需要自己创建2>&1
的效果,但正如你将在下面看到的那样,这很简单。
#! /usr/bin/perl
use warnings;
use strict;
my $pid = open my $fromgcc, "-|";
die "$0: fork: $!" unless defined $pid;
if ($pid) {
while (<$fromgcc>) {
print "got: $_";
}
}
else {
# 2>&1
open STDERR, ">&STDOUT" or warn "$0: dup STDERR: $!";
no warnings "exec"; # so we can write our own message
exec "gcc", @ARGV or die "$0: exec: $!";
}
Windows专有does not support open FH, "-|"
,但Cygwin非常乐意:
$ ./gcc.pl foo.c got: gcc: foo.c: No such file or directory got: gcc: no input files
答案 2 :(得分:1)
如果你提供其中任何一个参数数组(而不是单个字符串),它会直接调用Unix execve()函数或近亲,而不会让shell解释任何内容,完全按照你的需要去做
答案 3 :(得分:0)
感谢您的回答,我得出的结论是,我犯了一个很大的错误,我再次触摸了perl:浪费了数小时的时间来发现它无法正常完成。
与使用MS stdlib(在win32上是标准的)的所有其他应用程序相比,Perl使用不同的方式来分割命令行参数。
由于一些命令行参数被解释为一个signle命令行参数,perl可以被解释为多个参数。这意味着我所要做的就是浪费时间,因为perl中的错误行为。如果我1)无法按原样访问原始命令行,并且2)perl没有正确拆分命令行参数,则无法正确完成此任务。
作为一个简单的测试:
script.pl """test |test"
win32上的 错误地将命令行解释为:
ARGV=['"test', '|test']
然而,Windows上正确的“答案”必须是
ARGV=['"test |test']
我使用了activestate perl,我还尝试了草莓perl的最新版本:两个都很糟糕。似乎msys附带的perl工作正常,很可能是因为它是针对mingw而不是cygwin运行时构建的?...
perl的问题和原因是它有buggy cmd行解析器,它不能在windows上运行没有关系cygwin支持与否。 我有一个简单的例子,环境变量(我无法控制)扩展到
perl gcc.pl -c "-IC:\ffmpeg\lib_avutil\" rest of args
Perl看到我只有两个args:-c和'-IC:\ ffmpeg \ lib_avutil“其余的args' 而任何符合要求的Windows实现接收第二个cmd行arg为:' - IC:\ ffmpeg \ lib_avutil \',这意味着perl对于我的简单情况来说是一大堆垃圾,因为它没有提供足够的方法来访问cmd行参数。我最好使用boost :: regex并直接在c ++中进行所有解析,至少我不会犯下像ne和!=这样的愚蠢错误来比较字符串等.Windows对命令行参数的转义规则很奇怪,但它们是windows和perl的标准,出于某些奇怪的原因不想遵循操作系统的规则。