Interakcja z zewnętrznymi programami to kluczowa cecha Perla, dziedziczona od momentu powstania języka w 1987 roku dla zadań administracji systemów i automatyzacji rutyn shell. Perl zapewnia kilka sposobów wykonania zewnętrznego polecenia: operator system, odwrotne apostrofy (``) lub qx//, funkcja open z potokiem oraz modułowe opakowania typu IPC::Open3.
Głównym problemem przy uruchamianiu procesów zewnętrznych jest poprawne uzyskanie wyjścia (stdout i stderr), obsługa błędów uruchamiania, bezpieczeństwo parametrów (aby uniknąć iniekcji) oraz różnice między synchronizacją a asynchronicznym wykonaniem.
Rozwiązanie polega na wyborze odpowiedniego sposobu dla konkretnego zadania. Dla prostych poleceń używają system lub odwrotnych apostrofów, dla bardziej skomplikowanych przypadków — moduły IPC::*:
Przykład kodu (czytanie wyjścia polecenia i obsługa błędów):
my $command = 'ls -l /tmp'; my $output = qx{$command}; if ($? == -1) { die "Błąd uruchomienia: $!"; } elsif ($? & 127) { warn sprintf "Polecenie zakończone sygnałem %d", ($? & 127); } else { print "Wyjście: $output"; }
Kluczowe cechy:
Czym różni się system od exec w Perlu?
Odpowiedź: system uruchamia polecenie w zewnętrznym procesie i zwraca kontrolę Perl po zakończeniu, podczas gdy exec całkowicie zastępuje bieżący proces Perl wykonywaną programem, kod Perl po nim nie jest wykonywany.
Przykład:
system('echo Witaj'); exec('ls', '-l'); # Koniec, skrypt Perl zastąpiony ls, dalej Perl nie działa
Czy można bezpiecznie przekazywać zmienne użytkownika do poleceń shell?
Odpowiedź: Tylko przy użyciu listy argumentów (a nie stringa) i unikając interpolacji w shell. W przeciwnym razie może wystąpić iniekcja poleceń.
# Bezpiecznie: system("ls", "-l", $user_supplied_dir); # Niebezpiecznie: system("ls -l $user_supplied_dir");
Jak można uzyskać zarówno stdout, jak i stderr od zewnętrznego polecenia?
Odpowiedź: Niezawodny sposób to użycie IPC::Open3 lub przekierowanie stderr do stdout na poziomie shell:
my $out = qx{ls /notexists 2>&1};
lub przez IPC::Open3 (bardziej uniwersalny i subtelny sposób).
Administrator przekazuje przez system("rm -rf $dir") wartość podaną przez użytkownika.
Zalety:
Wady:
Używa się system('rm', '-rf', $dir), $dir jest walidowane, wprowadza się logowanie.
Zalety:
Wady: