perl -pi -e 's/\r\n/\n/' skrypt perl -p -i.bak -e "s/\r//" plik [wersja dla DOSa]
perl -e "print 'Hello World'" perl -e "print \"Hello World\""
więcej informacji o skryptach przez WWW w dziale Internet.
$|=1;
Can't locate strict.pm in @INC (@INC contains: ...)
Oznacza to, że moduł (strict.pm) nie jest zainstalowany w miejscu gdzie powinien, tj. w ścieżkach wymienionych w @INC. Może to najczęściej oznaczać brak modułu (konieczność instalacji), lub konieczność wskazania ścieżki:
use lib 'sciezka';
./test.pl -a1 -b2
W skrypcie dostęp do argumentów jest poprzez wektor @ARGV, czyli w tym przypadku w $ARGV[0] będzie wartość "-a1". Do używania z duchem Unixa, tj. tak by wartość powyższego a była 1, służy poniższy schemat:
use Getopt::Std;
getopts("a:b:");
print "${opt_a}\n";
print "${opt_b}\n";
@linie_odpowiedzi = `/usr/bin/finger root`
$status_komendy = system ("/usr/bin/finger root");
open(IN,"/usr/bin/finger root |"); @linie_odpowiedzi=<IN>; close IN;
Nie należy stosować exec, bo nie zwraca, tzn. po wywołaniu tej funkcji nowy proces (program) zastępuje ten aktualnie wykonywany i następne polecenia po exec nie będą wykonane.
Jeśli chcemy wywołać skrypt poleceniem system i zobaczyć tekst:
use IPC::Run qw(run); my @cmd = qw(echo -n to ma iść na stdout); run \@cmd, \'', \my $out, \my $err or die "run <@cmd>: $!"; print "polecenie <@cmd> zwróciło '$out' na STDOUT i '$err' na STDERR\n";
Powyższy kod jest najbezpieczniejszy. Inny skrypt perla można też uruchomić:
$wynik = do "nazwaskryptu.cgi";
Do dwustronnej komunikacji z zewnętrznym programem, jeśli mamy możliwość jego modyfikacji służą funkcje IPC (man perlipc). Jeśli potrzeba udawać użytkownika w przykładzie z finger należy zamiast open użyć open2 (IPC::Open2) lub open3 (IPC::Open). Alternatywą jest moduł Expect.
$ENV{'PATH'} = '/bin:/usr/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; #bezpieczne środowisko
system('id'); # sprawdzenie kto wykonuje skrypt
$<=$>; # ustaw rzeczywiste id na efektywne id
$(=$)+0; # ustaw rzeczywiste gid na efektywne gid
system('id'); # sprawdzenie praw
działanie polega na uruchomieniu perla z odpowiednimi prawami najlepiej przez sudo (http://www.courtesan.com/sudo/), a w starszych wersjach z suidperl.
{
local $SIG{ALRM} = sub { die "TIMEOUT\n" };
alarm( 10 ); # maksymalny czas operacji w sekundach
eval {
# tutaj operacje które mogą trwać zbyt długo - np. łączenie się
# do odległego serwera
alarm(0); # wyłączamy timeout
};
if( $@ eq "TIMEOUT\n" ) {
# był timeout
}
elsif( $@ ) {
# był jakiś inny fatal error
}
else {
# było OK
}
}
To działa tak, że w przypadku gdy operacje wewnątrz eval{ } przekroczą zadany czas, system generuje sygnał ALRM, który z kolei powoduje wykonanie die i "wyskoczenie" poza eval{ }, z ustawieniem $@ na "TIMEOUT\n".
To rozwiązanie nie jest w 100% bezpieczne, bo obsługa sygnałów w perlu (ciągle) nie jest w 100% bezpieczna. Ale przy mało krytycznych zastosowaniach sprawdza się doskonale.
W środowisku Windows nie ma funkcji alarm, więc trzeba się posłużyć modułami serii Win32.
Do uruchamiania co jakiś czas lepszym rozwiązaniem jest zastosowanie np. crona.
Do funcji debug przyda się http://iijo.org/vimDebug/
Inne polecane edytory:
Dobre środowiska IDE:
perl -w skrypt.pl
#!/usr/local/bin/perl -w
Pomocne, choć dość uciążliwe jest stosowanie konstrukcji:
use warnings; use strict; use diagnostics -verbose;
Warto też zwrócić uwagę na sprawdzanie czy wywołanie funkcji powiodło się, czyli co ona zwróciła. Na przykład przy otwieraniu pliku można zastosować:
open PLIK,"plik.txt" or die "Otwarcie pliku: $!";
Testowanie struktur danych w programie ułatwia moduł Data::Dumper, np.:
use Data::Dumper; print Dumper(\@a);
Uruchamiając skrypt z opcją perla -d (podobnie jak wyżej -w) mamy do dyspozycji wbudowany debugger.
Do testowania skryptów CGI polecane jest sprawdzenie, czy przy wykonywaniu z linii komend, nie ma błędów oraz czy wyświetlane są odpowiednie nagłówki. Przykładowe wywołanie skryptu CGI z parametrem nazwa o wartości nowa:
./skrypt.cgi nazwa=nowa
Testowanie CGI można także wykonywać na lokalnym serwerze WWW np. dla systemu Windows. Bardziej polecane jest użycie serwera Apache ze względu na rozpowszechnienie i zgodność.
Do kontroli błędów skryptu dobrze jest go uruchomić z linii komend lub wstawić procedurę obsługi błędów (sygnału DIE) przez WWW:
$SIG{__DIE__} = sub {
die @_ if ! defined $^S; # blad w obsludze bledu
print "Content-type: text/plain\n\n"; # naglowek dla WWW
print "Blad: $_\n"; # opis bledu
}
Powyższe można także uzyskać stosując w skrypcie linię
use CGI::Carp 'fatalsToBrowser';
W CPANie znajduje się moduł CGI::Debug, dzięki któremu możemy sprawdzić co jest nie tak w skrypcie umieszając linię:
use CGI::Debug(report =>'everything', on=>'errors');
ftp://sunsite.icm.edu.pl/pub/CPAN/ports/index.html#win32
Dla WIN 32 to doradza się: ActivePerl for x86 ze strony http://www.activestate.com/ lub http://theoryx5.uwinnipeg.ca/ppms/
Mały perl (560 kB) jest pod adresem http://www.mhuffman.com/resource/perl/perlmin586.zip
Dla zwolenników mod_perla przyda się adres ftp://theoryx5.uwinnipeg.ca/pub/other pod którym znajduje się jego wersja dla tego systemu, a także moduły bazujące na mod_perlu.
perldoc perlmodlib
Listę niestandardowych (dodatkowych) modułów zainstalowanych można uzyskać po wydaniu polecenia:
perldoc perllocal
Komenda
perl -Mnazwa_modulu -e 'print "OK\n"'
sprawdzi czy moduł da się załadować. Natomiast komenda szukająca plików o rozszerzeniu .pm w katalogach związanych z perlem (@INC) to:
perl -e "foreach \$path (@INC) { system(\"find \$path -name '*.pm'\") }"
Ewentualnie można objerzeć wynik komendy
perl -MCPAN -e autobundle
Lista standardowych modułów dla ActivePerla jest znacznie większa niż dla wersji dla Unixa. Lista tych pierwszych jest pod:
Instalacja standardowo po ściągnięciu z CPANu (np. GD):
gzip -cd GD*.tar.gz |tar xvf - cd GD-cośtam # to co się zrobiło po rozpakowaniu perl Makefile.PL # jesli chcemy na swoim koncie: perl Makefile.PL LIB=~/lib make make test # opcjonalnie make install # do tego trzeba odpowiednie prawa (zwykle root)
Szybciej:
perl -MCPAN -e shell cpan> i /GD/ [wyniki] cpan> install GD
Przy pierwszym uruchomieniu moduł CPAN wymaga konfiguracji i zapisuje ją w pliku CPAN/Config.pm w swoim katalogu bibliotecznym. Dla instalacji niestandardowej można go skopiować jako $HOME/.cpan/CPAN/MyConfig.pm i poprawić.
Dla perla z Activestate, lista: http://aspn.activestate.com/ASPN/Modules instalacja (online):
ppm PPM>install GD PPM>quit
offline:
ppm install GD.ppd
Dla tej wersji Perla istnieje sporo modułów tylko dla Windows z serii Win32::* opisanych w książce "Perl dla administratorów systemów".
Dla modułów zainstalowanych niestandardowo należy w skrypcie podać ścieżkę do nich (i jest ona pierwsza na liście) np.:
use lib "$ENV{HOME}/lib";
use Nazwa::Modułu;
Pierwszą linię można zapisać też jako:
BEGIN { unshift(@INC,"$ENV{HOME}/lib") }
lub zastąpić ustawieniem zmiennej PERLLIB lub PERL5LIB.
Do każdej instalacji z CPANu konieczny jest program make (standardowy w *nixie), dla windows używamy borlandowego dmake, lub microsoftowego nmake.
Kolejność z nmake jest następująca:
perl Makefile.PL nmake nmake test nmake install
perl -MCPAN -e 'print join "\n", keys %CPAN::'
to dla modułu CPAN, zaś nazwy funkcji:
perl -MCPAN -e 'print join "\n", grep *{$CPAN::{$_}}{CODE}, keys %CPAN::'
use POSIX; #czesc dzialajaca normalnie fork() and exit(); # rozgalezienie procesu i zakonczenie glownego setsid(); # nowa sesja # zamkniecie urzadzen we/wy close(STDIN); close(STDOUT); close(STDERR); #czesc wykonujaca prace w tle
Gotowy do wykorzystania moduł to Net::Server::Daemonize
Ponieważ na DOS/Win powyższy przykład nie działa, używa się modułu Win32::Process:
use Win32; use Win32::Process;
$perlPath = 'C:/perl/bin/perl.exe'; # Sciezka do perla $skrypt = 'perl -w D:/ppm/test_dbf/import.pl'; # Wywolywany skrypt $workDir = 'D:/ppm/test_dbf'; #Katalog roboczy
Win32::Process::Create($Win32::Process::Create::ProcessObj,
$perlPath,
$skrypt,
0,
DETACHED_PROCESS,
$workDir) or die print_error();
sub print_error { return Win32::FormatMessage(Win32::GetLastError()); }
Do postawienia serwisu na NT przyda się moduł Win32::Deamon ze strony http://www.roth.net
$|++;
@a=("|","/","-","\\");
while(1) {
print $a[0];
push@a, shift @a;
sleep 1;
print "\b";
}
lub
$|++;
@a=("|","/","-","\\");
while(1) {
print "$a[$i++]\r";
$i%=4;
sleep 1;
}
Wątki współdzielą pamięć. Czyli jak w jednym wątku zmienisz wartość zmiennej globalnej, to wszystkie inne wątki (z danego procesu) będą tą zmianę widzieć.
To oznacza dużo prostszą komunikację między wątkami (nie trzeba kombinować z pamięcią dzieloną/socketami/sygnałami), ale zarazem pojawiają się problemy z synchronizacją (wszystkie operacje na zmiennych globalnych trzeba zabezpieczać semaforami).
Poza tym wątki są dużo tańsze, tzn. utworzenie nowego wątku jest dużo mniej kosztowne niż utworzenie nowego procesu. No i oczywiście zajmują mniej zasobów niż procesy.
$| = 1;
$SIG{ALRM} = sub { print '#'; alarm 1; };
print "Zaczynam\n";
alarm 1;
for (1..10000000) { }; # cos dlugiego
# skonczone, kasujemy alarm i obsluge
alarm 0;
delete $SIG{ALRM};
print "Skonczylem\n";
W środowisku Windows nie ma funkcji alarm, więc trzeba się posłużyć modułami serii Win32.
use POSIX qw(:errno);
if( ! kill( 0, $X ) && $! == ESRCH ) { print "procesu nie ma"; }
else { print "proces jest"; }
$wynik = `ps aux`;
Alternatywą jest moduł Proc::ProcessTable.
# do konwersji numer procesu -> deskryptor my %pid2fh; no strict 'refs';
for my $i ( 1..10 ) {
#otwarcie potoku do czytania i rozdwojenie procesu
my $pid = open( "F$i", "-|" );
if( $pid ) { $pid2fh{$pid} = "F$i"; } #zapis deskryptora jesli rodzic
else {
my $timeout = int rand 10; # losowe opoznienie
exec "sleep $timeout; echo 'Hello, I am $$'"; # zakonczenie napisem
};
}
while( 1 ) {
my $pid = wait; # czekaj na potomka
last if $pid < 0; # jesli nie ma zadnego koniec petli
# proces $pid zakończył działanie, czytamy co zrobił...
my $fh = $pid2fh{$pid};
while(<$fh>) { print "[$pid]: $_"; }
}
open F, "-|" powoduje "rozforkowanie" procesu, w procesie potomnym wynikiem tej funkcji jest 0 (co wykorzystujemy powyżej aby uruchomić zadanie zewnętrzne przez system - exec byłby tu optymalniejszy), natomiast proces pierwotny otrzymuje jako wynik funkcji pid procesu potomnego. Co ważniejsze, tak stworzony proces ma od razu swoje standardowe wyjście podpięte do otwartego właśnie filehandle, więc możemy z niego czytać.
Funkcja wait zwraca pid procesu który się zakończył, lub -1 jeżeli nie ma już żadnych działających procesów potomnych (jeżeli są procesy potomne ale żaden się jeszcze nie skończył, funkcja wait zatrzymuje się aż do czasu zakonczenia jednego z procesów potomnych).
Do komunikacji dwustronnej można wykorzystać funkcję open2 oraz manual perlipc.
perlcc (freeware wraz z perlem) perlapp (licencja: 195$, tydzień free) http://www.activestate.com/Products/Perl_Dev_Kit/index.html perl2exe (licencja pro: 149$, lite: 49$) http://www.indigostar.com/perl2exe.htm p2xstd.exe (???)
perlapp i perl2exe potrafią tworzyć biblioteki dll, przez co skrypt jest mniejszy. Czasem trzeba deklarować niepotrzebne normalnie biblioteki lub wydać polecenie:
perl2exe_include IO/File.pm
lub umieścić w kodzie komentarz:
use Archive::Zip; #perl2exe
Skrypt po skompilowaniu jest nieczytelny dla człowieka, nie potrzeba do jego wykonania interpretera, zajmuje przeciętnie około 1MB. Nie jest to jednak żadne zabezpieczenie przed próbami odczytania kodu źródłowego (np. moduł B::Deparse) http://www.perlmonks.com/index.pl?node_id=237943 http://www.perlmonks.com/index.pl?node_id=232983 Lepiej do tegu użyć pakietu PAR, Filter, ACME lub SHC.
Skompilowany skrypt jest przydatny gdy nie chcemy instalować perla.
Alternatywą polecaną zamiast perl2exe jest użycie pakietu PAR.
#!/usr/bin/perl -pi.bak
BEGIN{ @ARGV or print "\nusage: ./wciecia.pl filename\n\n" and exit; }
s/^\s*/"\t" x $count/e;
$count += tr/{// - tr/}//;
Inne rozwiązanie to kompilacja, która jest procesem odwracalnym. Jedynie wstawienie skryptu przez WWW, tak że widoczne są tylko wyniki jego działania, zabezpiecza przed dostępem do kodu źródłowego.