Wyszukiwanie i zastępowanie z Perlem
Napisał: Patryk Krawaczyński
07/08/2009 w Hacks & Scripts Brak komentarzy. (artykuł nr 121, ilość słów: 613)
P
rzedstawiony hack jest tłumaczeniem “Global Search and Replace with Perl” z książki “Linux Servers Hacks” autorstwa Rob’a Flickenger’a udostępnionym on-line (Hack #73) na stronie http://hacks.oreilly.com. Do tłumaczenia zostało dodane także parę informacji od tłumacza.
Istnieje grupa parametrów, które czynią język Perl bardzo przydatnym narzędziem do edycji linii poleceń. Naucz się tych parametrów, i Ty wtedy dowiesz się jak wymruknąć magiczne, jednowierszowe skrypty Perla by pogmatwać plany przyjaciół (i wystraszyć twojego szefa projektu).
Pierwszym z nich jest -e. Daj Perlowi -e, a za nim wiersz kodu i uruchomi się jak zwykły skrypt Perl:
rob@catlin:~$ perl -e 'print "Hi, Ma!\n"' Hi, Ma!
Zapamiętaj sobie, że kończący znak ; nie jest potrzebny w jednoliniowcach. Generalnie dobrze jest umieścić twoją linię w pojedynczych cudzysłowach, aby zapobiec interpretowania przez powłokę znaków specjalnych (takich jak ! oraz \ powyżej).
Następny parametr jest trochę bardziej skomplikowany, ale stanie się twoją drugą naturą od kiedy zaczniesz go używać: -p. Z dokumentacji perldoc perlrun:
-p powoduje, że Perl uznaje następującą pętle w twoim programie, która powoduje iterację po argumentach nazw plików po trochu jak sed: LINE: while (<>) { ... # twoj program idzie tutaj } continue { print or die "-p przeznaczenie: $!\n"; }
Linia w wierszu ($_) jest automatycznie wyświetlana w każdej interracji pętli. Jeśli połączysz kombinację parametrów -p i -e, otrzymasz jednowierszowy skrypt iterujący po każdym pliku w wierszu poleceń lub następującym po nim tekście podanym do niego przez STDIN. Dla przykładu skomplikowane polecenie cat:
rob@catlin:~$ perl -pe 1 /etc/hosts # # hosts This file describes a number of hostname-to-address # mappings for the TCP/IP subsystem. # # For loopbacking. 127.0.0.1 localhost
Jedynka (1) to po prostu kod powrotu (jeśli wprowadziłeś 1; w skrypcie Perla, która jest równoważna: return 1;). Ponieważ wiersze są drukowane automatycznie, program określony parametrem -e nie musi robić nic więcej.
Momentem, w którym robi się ciekawie jest podawanie kodu manipulującego aktualnym wierszem przed jego wyświetleniem. Dla przykładu, załóżmy, że chcesz dołączyć nazwę lokalnej maszyny do wiersza localhost:
rob@catlin:~$ perl -pe 's/localhost/localhost $ENV{HOSTNAME}/' /etc/hosts # # hosts This file describes a number of hostname-to-address # mappings for the TCP/IP subsystem. # # For loopbacking. 127.0.0.1 localhost catlin.nocat.net
lub może chciałbyś zmienić twoje ustawienia daemona inetd:
rob@caligula:~$ perl -pe 's/^(\s+)?(telnet|shell|login|exec)/# $2/' \ \ /etc/inetd.conf
Wyświetli to zawartość pliku /etc/inetd.conf na STDOUT, umieszczając w komentarzach wszystkie nie zakomentowane wiersze telnet, shell, login lub exec po drodze. Naturalnie, możemy to przekierować z powrotem do pliku, ale jeśli chcemy tylko poddać edycji plik, istnieje lepszy sposób: parametr -i.
-i
pozwala na edycję plików w miejscu. A więc, aby zakomentować wszystkie powyższe linie w /etc/inetd.conf, możesz spróbować:
root@catlin:~# perl -pi -e 's/^(\s+)?(telnet|shell|login|exec)/# $2/' \ /etc/inetd.conf
lub nawet lepiej:
root@catlin:~# perl -pi.orig -e 's/^(\s+)?(telnet|shell|login|exec)/# $2/' \ /etc/inetd.conf
Drugi przykład powoduje utworzenie kopii zapasowej pliku /etc/inetd.conf w pliku /etc/inetd.conf.orig przed zmianą oryginału. Nie zapomnij przesłać sygnału HUP do daemona inetd, w celu uwzględnienia zmian.
Tak samo łatwa jest edycja wielu plików w miejscu, w tym samym czasie. Możesz podać każdą liczbę plików (lub dzikich kart / symboli wieloznacznych) w wierszu poleceń:
rob@catlin:~$ perl -pi.bak -e 's/bgcolor=#ffffff/bgcolor=#000000/i' *.html
To polecenie spowoduje zmianę koloru tła wszystkich stron html w bieżącym z białego koloru na czarny. Nie zapomnij o końcowym znaku i, dzięki któremu wzorzec jest rozpoznawany bez względu na wystąpienie wielkich i małych liter (tak samo traktuje się bgcolor=#FFFFFF i BGColor=#FfFffF).
A, co jeśli jesteś w trakcie pracy nad projektem CVS i potrzebujesz zmienić serwer CVS, na którym zatwierdasz poprawki? Proste, jeśli skierujesz potokiem wyjście polecenia find poprzez polecenie xargs uruchamiając polecenie: perl -pi e:
schuyler@ganesh:~/nocat$ find -name Root | xargs perl -pi -e \ 's/cvs.oldserver.com/cvs.newserver.org/g'
Następnie zresetuj zmienną $CSVROOT i normalnie wyrejestruj plik z repozytorium CVS. Projekt zostanie potem automatycznie zarejestrowany w cvs.newserver.org.
Perl w wierszu poleceń może posłużyć do wykonania bardzo skomplikowanych operacji przekształceń. Naucz się wyrażeń regularnych i korzystaj z nich mądrze. W ten sposób unikniesz tysięcy niepotrzebnych edycji ręcznych.
Więcej informacji: Perl, man perldoc, perlrun, Hacks O’Reilly