如何获取整个命令行字符串?

时间:2010-06-26 05:56:41

标签: perl command-line command-line-arguments

我正在编写一个模仿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

4 个答案:

答案 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)

perlipc文档中的

"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)

阅读exec函数和Perl中的system函数。

如果你提供其中任何一个参数数组(而不是单个字符串),它会直接调用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的标准,出于某些奇怪的原因不想遵循操作系统的规则。