【问题标题】:How can Perl's system() print the command that it's running?Perl 的 system() 如何打印它正在运行的命令?
【发布时间】:2010-09-06 05:50:55
【问题描述】:

在 Perl 中,您可以使用 system() 或 ``(反引号)来执行系统命令。您甚至可以将命令的输出捕获到变量中。但是,这会在后台隐藏程序执行,因此执行脚本的人看不到它。

通常这很有用,但有时我想看看幕后发生了什么。您是如何做到的,以便将执行的命令打印到终端,并将这些程序的输出打印到终端?这将是 .bat 相当于“@echo on”。

【问题讨论】:

    标签: perl system


    【解决方案1】:

    我不知道执行此操作的任何默认方式,但您可以定义一个子例程来为您执行此操作:

    sub execute {
        my $cmd = shift;
        print "$cmd\n";
        system($cmd);
    }
    
    my $cmd = $ARGV[0];
    execute($cmd);
    

    然后看看它的实际效果:

    pbook:~/foo rudd$ perl foo.pl ls
    ls
    file1   file2   foo.pl
    

    【讨论】:

      【解决方案2】:

      据我了解,system() 将打印命令的结果,但不会分配它。例如。

      [daniel@tux /]$ perl -e '$ls = system("ls"); print "Result: $ls\n"'
      bin   dev  home  lost+found  misc  net  proc  sbin     srv  System  tools  var
      boot  etc  lib   media       mnt   opt  root  selinux  sys  tmp     usr
      Result: 0
      

      反引号将捕获命令的输出而不是打印它:

      [daniel@tux /]$ perl -e '$ls = `ls`; print "Result: $ls\n"'
      Result: bin
      boot
      dev
      etc
      home
      lib
      

      等等……

      更新:如果你想打印命令名称为 system() 'd 为好,我认为Rudd 的方法很好。在此重复以进行合并:

      sub execute {
          my $cmd = shift;
          print "$cmd\n";
          system($cmd);
      }
      
      my $cmd = $ARGV[0];
      execute($cmd);
      

      【讨论】:

        【解决方案3】:

        改用 open 。然后你可以捕获命令的输出。

        open(LS,"|ls");
        print LS;
        

        【讨论】:

          【解决方案4】:

          这是一个更新的执行,它将打印结果并返回它们:

          sub execute {
            my $cmd = shift;
            print "$cmd\n";
            my $ret = `$cmd`;
            print $ret;
            return $ret;
          }
          

          【讨论】:

            【解决方案5】:

            嗯,有趣的是,不同的人以不同的方式回答这个问题。在我看来,mkDaniel Fone 将其解释为想要查看/操作命令的标准输出(他们的解决方案都没有捕获标准错误 fwiw)。我认为Rudd 更接近了。您可以对 Rudd 的响应做出的一种改变是用您自己的版本覆盖内置的 system() 命令,这样您就不必重写现有代码来使用他的 execute() 命令。

            使用 Rudd 帖子中的 execute() 子程序,您可以在代码顶部添加类似这样的内容:

            if ($DEBUG) {
               *{"CORE::GLOBAL::system"} = \&{"main::execute"};
            }
            

            我认为这会起作用,但我不得不承认这是巫术,而且我已经有一段时间没有编写此代码了。这是我多年前编写的代码,用于在模块加载时拦截本地(调用命名空间)或全局级别的系统调用:

              # importing into either the calling or global namespace _must_ be
              # done from import().  Doing it elsewhere will not have desired results.
              delete($opts{handle_system});
              if ($do_system) {
                if ($do_system eq 'local') {
                  *{"$callpkg\::system"} = \&{"$_package\::system"};
                } else {
                  *{"CORE::GLOBAL::system"} = \&{"$_package\::system"};
                }
              }
            

            【讨论】:

            • 替换全局system命令最大的问题是system有一个复杂的原型,不能被用户指定的原型系统复制。因此,如果您将 system 替换为您的自定义版本,某些代码将无法正常工作。
            【解决方案6】:

            与答案中提到的其他技术相结合的另一种技术是使用tee 命令。例如:

            open(F, "ls | tee /dev/tty |");
            while (<F>) {
                print length($_), "\n";
            }
            close(F);
            

            这将打印出当前目录中的文件(作为tee /dev/tty 的结果)并打印出每个读取的文件名的长度。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-10-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-07-13
              • 1970-01-01
              • 2012-02-15
              相关资源
              最近更新 更多