Чтобы ответить на ваш ближайший вопрос, вы запутались в поведении по умолчанию оператора Perl system
.Обычно для оболочки очень удобно анализировать команду, но иногда, как вы видели, наличие нескольких уровней кодирования - это боль, или даже уязвимость безопасности .
Вы можете полностью отказаться от цитирования оболочки с помощью форм system LIST
и exec LIST
.В вашем случае измените код на
#! /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
Они невидимы, но у каждой строки вывода есть завершающий символ табуляции.
Делать то же самое в 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
, но в принципе все просто.Срез позволяет получать данные по нескольким индексам (в данном случае 0 и 1, , т.е. , первый и второй столбцы). оператор диапазона выражение 0 .. 1
соответствует списку 0 и 1. Если позже вы решите, что вам нужны первые четыре столбца, вы измените его на 0 .. 3
.
Вызовите подпрограмму выше, как в
print_first_two_columns "myfile", "file2";
Обратите внимание, что код не совсем эквивалентен: он не сохраняет конечные символы табуляции.
Из командной строкиеще проще:
$ perl -lane '$,="\t"; print @F[0,1]' myfile file2
1 2
foo bar
oui oui
a b
d e