Что каждый хакер Perl должен знать о жемчуге-ne?

Я использовал командную строку Perl с a -ne опция в течение многих лет, в основном в файлы текста процесса способами, которыми не может sed. Пример:

cat in.txt | perl -ne "s/abc/def/; s/fgh/hij/; print;" > out.txt

Я понятия не имею, где я изучил это, и только сегодня считал perlrun и нашел, что существуют другие формы (perl -pe например).

Что еще должно я знать о perl -ne?

19
задан brian d foy 6 February 2010 в 07:29
поделиться

6 ответов

perl -ne 'CODE' эквивалентно программе

while (<>) {
    CODE
}

perl -ane 'CODE' и perl - F / PATTERN / -ane - также хорошие идиомы, о которых следует знать. Они эквивалентны

while (<>) {
    @F = split /\s+/, $_;
    CODE
}

и

while (<>) {
    @F = split /PATTERN/, $_;
    CODE
}

. Пример: advanced grep :

perl -ne 'print if/REGEX1/&&!/REGEX2/&&(/REGEX3/||/REGEX4/&&!/REGEX5/)' input

perl -F/,/ -ane 'print if $F[2]==4&&$F[3]ge"2009-07-01"&&$F[3]lt"2009-08-01"' file.csv


Особенно умный пример, в котором используются несовпадающие фигурные скобки, здесь .

24
ответ дан 30 November 2019 в 02:36
поделиться

Опция -i позволяет делать изменения в строке:

 perl -i -pe 's/abc/def/; s/fgh/hij/' file.txt

или сохранять резервную копию:

 perl -i.bak -pe 's/abc/def/; s/fgh/hij/' file.txt
4
ответ дан 30 November 2019 в 02:36
поделиться

Есть одна важная вещь, которую нужно знать о скриптах perl -ne и perl -pe : они неявно используют <> .

"Почему это важно?" вы можете спросить.

Магический оператор <> использует форму open с двумя аргументами. Если вы помните, 2 arg open включает в себя спецификацию режима с именем файла в одном аргументе. Вызов старого стиля open FILE, $ foo уязвим для манипуляций с файловым режимом. В этом контексте особенно интересен режим | - вы открываете дескриптор канала для процесса, который вы выполняете.

Вы могли подумать: «Подумаешь!», Но это так.

  • Представьте себе задание cron, выполняемое пользователем root для изменения файлов журналов в каком-либо каталоге.
  • Сценарий вызывается как сценарий * .
  • Представьте себе файл в этом каталоге с именем | rm -rf / .

Что происходит?

  1. Оболочка раскрывает * , и мы получаем скрипт file_1 file_2 '| rm -rf /' file_4
  2. Скрипт обрабатывает file_1 и файл_2 .
  3. Затем он открывает дескриптор STDIN rm -rf / .
  4. За этим следует большая дисковая активность.
  5. file_4 больше не существует, поэтому мы не можем его открыть.

Конечно, возможности безграничны.

Вы можете прочитать более подробное обсуждение этого вопроса на Perlmonks .

Мораль истории: будьте осторожны с оператором <> .

FWIW, я только что подтвердил, что это все еще проблема с perl 5.10.0.

13
ответ дан 30 November 2019 в 02:36
поделиться

Вы можете указать более одного предложения -e. Иногда у меня есть командная строка, которая начинает расти по мере того, как я уточняю операцию поиска / извлечения / управления. если вы что-то напечатаете неправильно, вы получите "номер строки", указывающий, в каком -e есть ошибка.

Конечно, некоторые могут возразить, что если у вас более одного или двух предложений -e, возможно, вам стоит поместить все, что они есть, в сценарий, но некоторые вещи на самом деле просто выбрасываются, так зачем беспокоиться.

perl -n -e 'if (/good/)' -e '{ system "echo $_ >> good.txt"; }' \
-e 'elsif (/bad/)' -e '{ system "echo $_ >> bad.txt"; }' \
-e 'else' -e '{ system "echo $_ >> ugly.txt"; }' in.txt another.txt etc.txt

Предположительно, вы бы сделали что-то менее тривиальное, чем grep / egrep, в 3 файла: -)

6
ответ дан 30 November 2019 в 02:36
поделиться

Мне нравится думать о perl -n как о выборе определенных битов входа и perl -p как о map для всех строк входа.

Как вы заметили, можно получить эффект -p с -n, а можно эмулировать наоборот:

$ echo -e "1\n2\n3" | perl -pe '$_="" if $_ % 2 == 0'
1
3

Пропуск строк с -p казался бы более естественным, но -p код обёртывания в

LINE:
while (<>) {
    ...     # your program goes here
} continue {
    print or die "-p destination: $!\n";
}

По замыслу, -p выполняется -продолжение -блоки:

Если есть -продолжение BLOCK, то он всегда выполняется непосредственно перед тем, как условие снова будет вычислено. Таким образом, его можно использовать для инкремента переменной цикла, даже если цикл был продолжен с помощью следующего оператора .

Переключатель -l имеет два полезных эффекта:

  1. С -n и -p, автоматически chomp каждая входная запись.
  2. Установите $\, чтобы каждая распечатывала неявно добавляла терминатор.

Например, чтобы захватить первые 10 UDP-портов, упомянутых в /etc/services, вы можете

perl -ane 'print $F[1] if $F[1] =~ /udp/' /etc/services | head

, но ой:

7/udp9/udp11/udp13/udp17/udp19/udp37/udp39/udp42/ud...

Лучше:

$ perl -lane 'print $F[1] if $F[1] =~ /udp/' /etc/services | head
7/udp
9/udp
11/udp
13/udp
17/udp
19/udp
37/udp
39/udp
42/udp
53/udp

Помните, что -n и -p также могут быть в строке shebang, так что для сохранения вышеуказанного oneliner в качестве скрипта, сохраните его:

#! /usr/bin/perl -lan

BEGIN {
  @ARGV = ("/etc/services") unless @ARGV;
  open STDOUT, "|-", "head" or die "$0: head failed";
}

print $F[1] if $F[1] =~ /udp/
2
ответ дан 30 November 2019 в 02:36
поделиться

Моя любимая ссылка на однострочники Perl (и первое место в Google по этой фразе) охватывает perl -ne: http://novosial.org/perl/one-liner/

1
ответ дан 30 November 2019 в 02:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: