如何在perl脚本中插入awk命令?

时间:2011-03-11 16:57:48

标签: linux perl awk

我想在我的脚本上添加这个awk命令,但不断收到错误。我已经放入“”但仍然出错。

system("awk -F"\t" '{ for ( i=1; i<=2; i++ ) { printf "%s\t", $i } printf "\n"; }' myfile file2"};

错误是

  

找到运营商预期的字符串   在host_parse第21行,靠近“t”'{for   (i = 1; i <= 2; i ++){printf“”

     

不带引号的字符串“a”可能会发生冲突   在myfile行的未来保留字   58。

     

不带引号的字符串“a”可能会发生冲突   在myfile行的未来保留字   58。

     在myfile第21行附近的

语法错误   “”awk -F“\”

感谢。

3 个答案:

答案 0 :(得分:7)

使用system命令最棘手的部分之一是使用引号,以便将正确的命令传递给操作系统。 Perl的q//构造对此非常有帮助:

# treat everything between the @...@ as uninterpolated string
system( q@awk -F"\t" '{ for ( i=1; i<=2; i++ ) { printf "%s\t", $i } 
          printf "\n"; }' myfile file2@ );

答案 1 :(得分:2)

要回答您的直接问题,您将绊倒Perl的system运算符的默认行为。通常,shell可以很方便地解析命令,但有时候,正如您所见,多级编码很痛苦 - 甚至是security vulnerability

您可以完全使用system LISTexec LIST表单绕过shell的引用。在您的情况下,将代码更改为

#! /usr/bin/env perl

use strict;
use warnings;

my @cmd = (
  "awk",
  "-F", "\t",
  '{ for ( i=1; i<=2; i++ ) {
       printf "%s\t", $i
     }
     printf "\n";
   }',
   "myfile", "file2",
);

system(@cmd) == 0 or warn "$0: awk exited " . ($? >> 8);

您不必使用临时数组,但我不喜欢使用多行命令生成的代码并检查是否成功。

鉴于myfile包含

1  2   3   4
foo bar baz
oui oui monsieur

file2

a   b   c
d   e   f   g

(两种情况下的分隔符都是TAB字符),则输出为

1  2   
foo bar 
oui oui 
a   b   
d   e   

它们是不可见的,但上面的每一行输出都有一个尾随的TAB。

在Perl中执行相同操作非常简单。例如,

sub print_first_two_columns {
  foreach my $path (@_) {
    open my $fh, "<", $path or die "$0: open $path: $!";

    while (<$fh>) {
      chomp;
      my(@cols) = (split /\t/)[0 .. 1];
      print join("\t", @cols), "\n";
    }

    close $fh;
  }
}

可能不明显的部分是从split返回的slice值,但正在发生的事情在概念上很简单。切片允许您以多个索引(在本例中为0和1,,第一列和第二列)获取数据。 range-operator表达式0 .. 1计算到列表0和1.如果您稍后决定要第一个四个列,则将其更改为0 .. 3

中调用上面的子目录
print_first_two_columns "myfile", "file2";

请注意,代码并不完全等效:它不会保留尾随的TAB字符。

从命令行来看,它甚至更简单:

$ perl -lane '$,="\t"; print @F[0,1]' myfile file2 
1   2
foo bar
oui oui
a   b
d   e

答案 2 :(得分:1)

您不需要shell来解释任何重定向(或其他shell设施),因此最好将参数列表传递给system()

system 'awk', '-F', "\t", 
   '{for (i=1; i<=2; i++) {printf "%s\t", $i}; print ""}',
   'myfile', 'file2';