Co każdy haker Perla powinien wiedzieć o perl-ne?

Używam wiersza poleceń Perla z opcją -ne od lat, głównie do przetwarzania plików tekstowych w sposób, w jaki sed nie może. Przykład:

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

Nie mam pojęcia, gdzie się tego nauczyłem i dopiero dziś przeczytałem perlrun i znalazłem Inne formy (perl -pe na przykład).

Co jeszcze powinienem wiedzieć o perl -ne?

Author: brian d foy, 2010-02-06

7 answers

perl -ne 'CODE' jest odpowiednikiem programu

while (<>) {
    CODE
}

perl -ane 'CODE' i perl -F/PATTERN/ -ane są również dobrymi idiomami, o których warto wiedzieć. Są równoważne

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

I

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

Przykład: zaawansowany 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


Szczególnie sprytnym przykładem, który używa niedopasowanych szelek jest tutaj .

 22
Author: mob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:14

Jest jedna ważna rzecz, którą należy wiedzieć o skryptach perl -ne i perl -pe: domyślnie używają <>.

"dlaczego to jest ważne?"możesz zapytać.

Magiczny operator <> używa 2 arg Formy Otwartej. Jeśli pamiętasz, 2 ARG open zawiera specyfikację mode z nazwą pliku w jednym argumencie. Wywołanie w starym stylu {[4] } jest podatne na manipulację trybem plików. Szczególnie interesującym trybem w tym kontekście jest | -- otwierasz uchwyt do rury do procesu wykonujesz egzekucję.

Możesz myśleć " wielka sprawa!", ale jest.

  • wyobraź sobie zadanie crona wykonywane przez roota do plików dziennika munge w jakimś katalogu.
  • skrypt jest wywoływany jako script *.
  • wyobraź sobie plik w katalogu o nazwie |rm -rf /.
Co się dzieje?
  1. powłoka rozszerza * i otrzymujemy script file_1 file_2 '|rm -rf /' file_4
  2. skrypt przetwarza file_1 i file_2.
  3. następnie otwiera uchwyt na STDIN z rm -rf /.
  4. dużo aktywność dysku następuje.
  5. file_4 już nie istnieje, więc nie możemy go otworzyć.
Oczywiście możliwości są nieograniczone.

Możesz przeczytać więcej dyskusji na ten temat na Perlmonks .

Morał historii: uważaj na operatora <> .

FWIW, właśnie potwierdziłem, że nadal jest to problem z perlem 5.10.0.

 12
Author: daotoad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-07 06:37:38

Możesz podać więcej niż jedną klauzulę-E. Czasami mam wiersz poleceń, który zaczyna rosnąć, gdy udoskonalam operację wyszukiwania / wyodrębniania / mangulacji. jeśli coś pomylisz, otrzymasz "numer linii" informujący, które -e ma błąd.

Oczywiście niektórzy mogą twierdzić, że jeśli masz więcej niż jedną lub dwie klauzule e, może powinieneś umieścić cokolwiek to jest w skrypcie, ale niektóre rzeczy naprawdę są po prostu wyrzucane, więc po co się trudzić.

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

Prawdopodobnie zrobiłbyś coś mniej trywialne niż grep / egrep w 3 plikach: -)

 6
Author: Roboprog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-06 08:07:04

Opcja -i pozwala na wykonanie zmian w linii:

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

Lub zapisz kopię zapasową:

 perl -i.bak -pe 's/abc/def/; s/fgh/hij/' file.txt
 4
Author: jojo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-06 11:43:41

Lubię myśleć o perl -n jako o wybraniu konkretnych bitów wejścia i perl -p jako map dla wszystkich linii wejścia.

Jak zauważyliście, możliwe jest uzyskanie efektu -p z -n, a my możemy emulować na odwrót:

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

Pomijanie linii z next wydaje się bardziej naturalne, ale -p owija kod w

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

Według projektu, next Działa continue bloki:

Jeśli istnieje continue blok, jest zawsze wykonywany tylko przed ponowną oceną warunku. W ten sposób można go wykorzystać do zwiększenia zmiennej pętli, nawet jeśli pętla jest kontynuowana za pomocą instrukcji next.

Przełącznik -l ma dwa przydatne efekty:

  1. Z -n i -p, automatycznie chomp każdy rekord wejściowy.
  2. Set $\ więc każdy print domyślnie dodaje terminator.
Na przykład, aby pobrać pierwsze 10 portów UDP wymienionych w /etc/services, możesz
perl -ane 'print $F[1] if $F[1] =~ /udp/' /etc/services | head

Ale UPS:

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

Lepiej:

$ 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

Pamiętaj, że -n i -p mogą być również w linii shebang, więc aby zapisać Powyższy tekst jako skrypt:

#! /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
Author: Greg Bacon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-06 13:22:00

Moja ulubiona Referencja do linerów Perl one (i top hit w Google za tę frazę) obejmuje perl -ne: http://novosial.org/perl/one-liner/

 1
Author: Philip Durbin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-13 02:30:57

Często używam sed lub awk ale bardzo podoba mi się Ta perl pasująca funkcja pattern killer:

$ cat my-input.txt
git 111 HERE 2222 voila 333
any 444 HERE none start 555 HERE 6
svn 777 aaaa 8888 nothing
two 222 HERE 9999 HERE 0000

$ perl -nle 'print $a if (($a)=/HERE ([0-9]+)/)' my-input.txt
2222
6
9999
 1
Author: olibre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-21 16:31:57