2016-06-27 3 views
9

perl interpretuje samego Shebang i naśladuje zachowanie exec*(2). Wydaje mi się, że emuluje zachowanie Linuxa dzielenia na wszystkie białe znaki zamiast na pierwszą białą, ale nieważne.W jaki sposób Perl unika pętli shebang?

Podobnie jak szybki demonstracji really_python.pl

#!/usr/bin/env python 

# the following line is correct Python but not correct Perl 
from collections import namedtuple 
print "hi" 

drukuje hi Wywołany jako perl really_python.pl.

Ponadto następujące programy postąpią właściwie, niezależnie od tego, czy są wywoływane jako perl program lub ./program.

#!/usr/bin/perl 
print "hi\n"; 

i

#!/usr/bin/env perl 
print "hi\n"; 

Nie rozumiem, dlaczego program nie jest nieskończone zapętlenie. W każdym z powyższych przypadków linia półksiężyca jest równa lub ustala bezwzględną ścieżkę do interpretera perl. Wygląda na to, że następną rzeczą, która powinna się stać, jest to, że perl analizuje plik, zauważa shebang i deleguje na ścieżkę shebang (w tym przypadku samą w sobie). Czy perl porównać ścieżkę shebang do własnej ARGV[0]? Czy perl przyjrzeć się ciągowi shebang i sprawdzić, czy zawiera on podciąg "perl"?

Próbowałem użyć dowiązania symbolicznego do wyzwolenia nieskończonej pętli, której oczekiwałem.

$ ln -s /usr/bin/perl /tmp/p 

#!/tmp/p 
print "hi\n"; 

ale ten program wydrukował "cześć" bez względu na to, jak został wywołany.

Jednak na OS X udało mi się oszukać perl w nieskończoną pętlę shebang ze skryptem.

Zawartość /tmp/pscript

#!/bin/sh 
perl "[email protected]" 

treści skryptu perla

#!/tmp/pscript 
print "hi\n"; 

i to robi nieskończonej pętli (na OS X, nie testowałem go jeszcze w systemie Linux).

perl z pewnością zadałby dużo trudu, by poprawnie poradzić sobie z bzdurami w uzasadnionych sytuacjach. Nie jest to mylone przez dowiązanie symboliczne i nie jest mylone ze zwykłymi rzeczami z env. Co dokładnie robi?

Odpowiedz

10

Odpowiedni kod jest toke.c, lexer Perl. Gdy:

  • linia 1 zaczyna #! (ewentualnie poprzedzona spacji) I

  • nie zawiera perl - I

  • nie zawiera perl (chyba, że ​​następuje 6 tj perl6) I

  • (na platformach "DOS") nie zawiera rozróżniania wielkości liter od perl (np. Perl) I

  • nie zawiera indir I

  • flaga -c nie był ustawiony w linii poleceń i

  • argv[0] zawiera perl

programu po shebang jest wykonane z execv. W przeciwnym razie lexer po prostu idzie dalej; perl nie jest sam w sobie.

W rezultacie, można zrobić kilka bardzo dziwne rzeczy z shebang bez Perl próbujących exec innego tłumacza:

#!  perl 
#!foo perl 
#!fooperlbar -p 
#!perl 6 
#!PeRl   # on Windows 

Twój przykład symlink spełnia wszystkich warunków wymienionych powyżej, więc dlaczego ISN nie ma nieskończonej pętli? Można zobaczyć, co się dzieje z strace:

$ ln -s /usr/bin/perl foo 
$ echo '#!foo' > bar 
$ strace perl bar 2>&1 | grep exec 
execve("/bin/perl", ["perl", "bar"], [/* 27 vars */]) = 0 
execve("foo", ["foo", "bar"], [/* 27 vars */]) = 0 

Perl faktycznie robi exec link, ale dlatego, że nie zawiera perl w nazwie, ostatni warunek nie jest już spotkał się po raz drugi wokół i końce pętli .

+0

Uwaga: Zakłada się, że OP uruchomił skrypt za pomocą 'perl/tmp/pscript'. Odpowiedź jest nieco inna, gdy skrypt jest uruchamiany za pomocą '/ tmp/pscript'. – ikegami

12

Dokumentacja dla tej funkcji znajduje się w perlrun.

Jeśli linia #! nie zawiera słowa „perla”, ani słowo „indir”, program o nazwie po #! jest wykonywany zamiast tłumacza Perl. To trochę dziwne, ale pomaga ludziom na maszynach, które nie robią #!, ponieważ mogą powiedzieć programowi, że ich SHELL jest /usr/bin/perl, a Perl następnie wyśle ​​program do właściwego tłumacza dla nich .

Tak więc, jeśli shebang zawiera perl lub indir interpreter z linii shebang nie jest wykonywany.

Additionally, interpreter z linii Shebang nie zostanie wykonany, jeśli argv[0] nie zawiera perl. To właśnie zapobiega nieskończonej pętli w twoim przykładzie.

  • Po uruchomieniu za pomocą perl /tmp/pscript,

    1. jądro wykonuje perl /tmp/pscript,
    2. następnie perl wykonuje /tmp/p /tmp/pscript.
    3. W tym momencie argv[0] nie zawiera perl, więc linia półbrzusza nie jest już istotna.
  • Po uruchomieniu za pomocą /tmp/pscript,

    1. jądro wykonuje /tmp/p /tmp/pscript.
    2. W tym momencie argv[0] nie zawiera perl, więc linia półbrzusza nie jest już istotna.
+0

I, od 5.24, słowo "perl6" nie jest uważane za dopasowanie dla "perl", co oznacza, że ​​jeśli program z perl6 shebang jest uruchamiany przez interpretera perl5, to będzie on ponownie wykonywał perl6, zamiast próbować uruchom sam. Wygląda na to, że 'perlrun' nie został zaktualizowany, aby to odzwierciedlić. – hobbs

+0

(Jeśli jesteś naprawdę zdeterminowany, aby uzyskać pętlę, prawdopodobnie możesz ją uzyskać przez dowiązanie symboliczne perl 5.24 jako "perl6", ponieważ warunek z zapadnięciem pętli * nie * ma ten wyjątek.) – hobbs

+0

@hobbs, Kod do które łączyłem dla 5.24. Więcej szczegółów można zobaczyć tam, w odpowiedzi ThisSuitIsBlackNot. Ograniczałem odpowiedź na zakres pytania, ale są też inne "ukryte" reguły. – ikegami