W pierwszych skryptach, które pisaliśmy, nie ma tego konstruktu, ale może on być przydatny w skryptach Perla na systemach uniksowych takich jak Linux czy Mac OSX.
Nie jest tak naprawdę wymagany, możesz po prostu ominąć ten artykuł i wrócić później, kiedy będziesz chciał zrozumieć co
znaczy #!/usr/bin/perl
na początku wielu skryptów Perla.
Zanim przejdę do szczegółów, pozwól mi powiedzieć, że tak linia jest także nazywana she-bang, Shebang lub sh-bang, a także innymi nazwami.
Pierwszy program, którego zwykle uczą się ludzie, to zwykle "Hello world". Oto skrypt:
use strict;
use warnings;
print "Hello World\n";
Możemy go zapisać do pliku nazwanego hello.pl
, otworzyć terminal (lub Cmd pod Windows). cd
do katalogu gdzie zapisaliśmy plik
i uruchomić skrypt przez wpisanie perl hello.pl
.
To znaczy, uruchamiamy Perla i mówimy mu, by wykonał nasz skrypt.
Czy byłoby możliwe wykonanie skryptu bez wcześniejszego uruchomienie perla? Czy byłoby możliwe po prostu uruchomić hello.pl
?
W systemach uniksowych jest to całkiem proste. Pod Windows jest to całkiem inna historia i zostanie poruszona oddzielnie.
hash-bang w systemach uniksowych
Spróbujmy uruchomić skrypt:
$ hello.pl
-bash: hello.pl: command not found
Nasze środowisko nie może znaleźć skryptu.
Co jeśli podamy ścieżkę do skryptu (który jest i tak w bieżącym katalogu):
$ ./hello.pl
-bash: ./hello.pl: Permission denied
Teraz już znajduje skrypt, ale nie ma uprawnień do jego uruchomienia.
Na Linuksie czy Mac OSX, czy każdym innym systemie uniksowym możemy uczynić skrypt "wykonywalnym" przez ustawienie bitu w standardowych atrybutach pliku
w tak zwanej tablicy inode'ów.
Można to łatwo zrobić używając polecenia chmod
. Użyjemy chmod u+x hello.pl
:
Najpierw użyjemy polecenia ls -l
powłoki Uniksa aby zobaczyć sytuację przed,
następnie użyjemy chmod
do zmiany uprawnień,
a na końcu sprawdzimy sytuację po tej operacji.
Część u+x
operacji mówi chmod aby dodał prawa wykonania (x) dla użytkownika (u), który jest właścicielem tego pliku,
ale dla nikogo innego. (chmod +x hello.pl
przyznałoby prawa wykonania każdemu w systemie.)
$ ls -l hello.pl
-rw-r--r-- 1 gabor staff 50 Apr 21 10:11 hello.pl
$ chmod u+x hello.pl
$ ls -l hello.pl
-rwxr--r-- 1 gabor staff 50 Apr 21 10:11 hello.pl
Zwróć uwagę na dodatkowy x
jako czwarty znak odpowiedzi.
Spróbujmy uruchomić skrypt ponownie:
$ ./hello.pl
./hello.pl: line 1: use: command not found
./hello.pl: line 2: use: command not found
./hello.pl: line 4: print: command not found
Znacznie lepiej :)
Teraz możemy już uruchomić skrypt, ale nie robi on tego, co chcemy. W rzeczywistości narzeka, że nie może
znaleźć poleceń 'use' ani 'print'. To co się tu wydarzyło to to, że powłoka, której używamy (prawdopodobnie bash) próbował
interpretować polecenia w pliku, ale nie znalazł takich poleceń jak use
czy print
w Linuksie/Uniksie. W jakiś sposób musimy powiedzieć powłoce, że jest to skrypt perlowy. Służy do tego hash-bang.
Jeśli wyedytujemy plik i dodamy
#!/usr/bin/perl
jako pierwszą linię skryptu i bez spacji, a następnie spróbujemy uruchomić skrypt ponownie:
$ ./hello.pl
Hello World
działa już jak oczekujemy.
Jednakże, jeśli spróbujemy uruchoić go bez ./
, nadal nie będzie mógł go znaleźć:
$ hello.pl
-bash: hello.pl: command not found
W celu rozwiązania tego musimy zmienić zmienną środowiskową PATH
. Jako, że skupiamy się głównie
na linii hash-bang, nie chcę wchodzić w dalsze dokładnie wyjaśnienia, więc pozwól, że po prostu podam Ci polecenie:
$ PATH=$PATH:$(pwd)
dołączające bieżący katalog do listy katalogów w zmiennej środowiskowej PATH. Gdy to zrobimy, możemy teraz uruchomić:
$ hello.pl
Hello World
Jak działa linia hash-bang?
Dodaliśmy #!/usr/bin/perl
jako pierwszą linię naszego skryptu:
Kiedy uruchamiamy skrypt, uruchamiamy go w środowisku naszej bieżącej powłoki. Dla większości ludzi pod Linuksem/Uniksem będzie to Bash.
Bash przeczyta pierwszą linię skryptu. Jeśli zaczyna się ona od hasha i wykrzyknikiem (hash-bang) #!
,
wówczas Bash uruchomi aplikację, której ścieżka jest w linii hash-bang (w naszym przypadku /usr/bin/perl
,
co jest standardową lokalizacją kompilatora-interpretera perl na większości współczesnych systemów Uniksowych).
Linia hash-bang zawiera ścieżkę do kompilatora-interpretera Perla.
Jeśli pierwsza linia nie zaczyna się od #!
, jak miało to miejsce w naszym pierwotnym skrypcie, Bash będzie przypuszczał,
że jest to skrypt napisany w Bashu i będzie próbował zrozumieć go samodzielnie. Właśnie to powodowało błędy.
Alternatywne linie hash-bang z użyciem env
Choć używaliśmy #!/usr/bin/perl
jako naszą linię hash-bang, może ona wyglądać inaczej. Na przykłąd jeśli zainstalowaliśmy
inną wersję perla w innej lokalizacji i chcemy, by nasze skrypty z niej korzystały, możemy podać ścieżkę
do tej wersji perla. Na przykład #!/opt/perl-5.18.2/bin/perl
.
Przewaga ustawienia hash-bang (i włączenia bitu wykonywalności) jest taka, że użytkownik nie musi
wiedzieć, że skrypt jest napisany w Perlu i jeśli masz wiele instancji Perla w swoim systemie,
linia hash-bang może zostać użyta do wybrania, która wersja perla ma być użyta. Będzie ona taka sama dla wszytkich
ludzi na danej maszynie.
Wada jest taka, że wersja perla wymieniona w linii hash-bang jest wykorzystywana tylko, gdy skrypt jest uruchamiany
jako ./hello.pl
lub jako hello.pl
.
Jeśli zostanie uruchomiony jako perl hello.pl
, wykorzysta wersję perla, która zostanie znaleziona jako pierwsza
w katalogach wymienionych w PATH. I może ona być inna, niż wersja perla z linii hash-bang.
Z tego powodu, na współczesnych systemach Linux/Unix, ludzie mogą preferować użycie #!/usr/bin/env perl
jako
linii hash-bang. Kiedy Bash zobaczy taką linię, najpierw wykona polecenie env
przekazując perl
do niego.
env
znajdzie pierwszego perla w katalogach PATH i uruchomi go.
Zatem jeśli mamy #!/usr/bin/env perl
w naszym skrypcie, zawsze będzie on korzystac z pierwszego perla w naszym PATH.
Zarówno, jeśli zostanie wywołany jako ./hello.pl
, jak i gdy zostanie wywołany przez perl hello.pl
.
Ma to także wadę, ponieważ polega na właściwym ustawieniu zmiennej PATH przez użytkowników.
Oto tabela, która próbuje wyjaśnić 4 przypadki:
hash-bang Który perl jest używany do uruchomienia skryptu przy wywołaniu:
./hello.pl perl hello.pl
/usr/bin/perl /usr/bin/perl pierwszy perl w PATH
/usr/bin/env perl pierwszy perl w PATH pierwszy perl w PATH
Flagi w linii hash-bang
W linii hash-bang, po ścieżce do perla, możemy przekazać perlowi flagi wiersza poleceń.
Prawdopodobnie zobaczysz wiele skrytpów zaczynających się od #!/usr/bin/perl -w
czy
może #!/usr/bin/env perl -w
.
-w
w tym hash-bangu włącza ostrzeżenia. Jest to zupełnie podobne do tego, co robi
use warnings, ale jest użyte w starym stylu.
Nie zobaczysz tego w większości współczesnych skryptów Perla.
Kolejne popularne flagi, które możesz zobaczyć w linii hash-bang to -t
i -T
. Włączają
one tak zwany taint-mode, który pomaga pisać bezpieczniejszy kod.