Как вставить команду awk в скрипт perl? - PullRequest
0 голосов
/ 11 марта 2011

Я хочу добавить эту команду awk в мой скрипт, но получаю сообщение об ошибке. Я положил внутрь "", но все еще получаю ошибку.

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

ошибки

Строка найдена там, где ожидается оператор в строке 21 host_parse, около "t" '{для (i = 1; i <= 2; i ++) {printf "" </p>

Строка без кавычек "a" может конфликтовать с будущее зарезервированное слово в строке myfile 58.

Строка без кавычек "a" может конфликтовать с будущее зарезервированное слово в строке myfile 58.

синтаксическая ошибка в строке 21 моего файла, рядом "" awk -F "\"

Спасибо.

Ответы [ 3 ]

7 голосов
/ 11 марта 2011

Одной из самых хитрых частей использования команды 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@ );
2 голосов
/ 11 марта 2011

Чтобы ответить на ваш ближайший вопрос, вы запутались в поведении по умолчанию оператора 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
1 голос
/ 11 марта 2011

Вам не нужна оболочка для интерпретации любого перенаправления (или других средств оболочки), поэтому было бы лучше передать список аргументов в system()

system 'awk', '-F', "\t", 
   '{for (i=1; i<=2; i++) {printf "%s\t", $i}; print ""}',
   'myfile', 'file2';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...