我想在我的脚本上添加这个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“\”
感谢。
答案 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 LIST
和exec 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';