2016-06-27 12 views
9

perlはシバンそのものを解釈し、振る舞いをexec*(2)と似ています。私は、BSDの最初の空白だけのものではなく、すべての空白で分割するというLinuxの動作をエミュレートすると思いますが、それは気にしないでください。ただ、really_python.plPerlはシボンループをどのように回避しますか?

#!/usr/bin/env python 

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

プリントがハイperl really_python.plとして呼び出された簡単なデモとして

また、次のプログラムは、perl programまたは./programとして呼び出されるかどうかに関係なく、適切な処理を行います。

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

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

プログラムが無限ループではない理由を私は理解していません。上記のいずれの場合でも、シバン線は、perlインタプリタへの絶対パスかそれに解決されます。その後、次のようなことが起こります。perlはファイルを解析し、シバンに気付き、シバンパス(この場合はそれ自体)に委任します。 perlはシバンパスを自分自身のARGV[0]と比較しますか? perlはシバン文字列を見て、部分文字列として"perl"が含まれているかどうかを確認しますか?

私が期待していた無限ループ動作をトリガするためにシンボリックリンクを使用しようとしました。

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

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

しかし、どのように呼び出されたかにかかわらず、そのプログラムは "hi"と表示されます。

OS Xでは、perlをスクリプトを使って無限のシバンループにトリックすることができました。 /tmp/pscript

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

のperlスクリプトの内容

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

、これは無限ループを行います(OS X上で、まだLinux上でそれをテストしていない)の

内容。

perlは、合理的な状況でシバンを正しく処理するためにはっきりと問題になります。シンボリックリンクとは混同されておらず、通常のenvのもので混乱しません。それは正確に何をしていますか?

答えて

10

関連するコードはtoke.c、Perlのレクサーです。場合:

  • ライン1は#!始まる(必要に応じて空白が先行)AND

  • perl - AND

  • 6続いない限りperl6すなわち、)perlが含まれていないが含まれていませんAND

  • ( "DOSish"プラットフォームの場合)は、大文字と小文字を区別しないの一致が含まれていません(例: Perl)AND

  • indir含まれておらず、

  • -cフラグがコマンドラインで設定されていませんでした

  • argv[0]がシェバングされ、次のperl

プログラムが含まれていますexecvで実行されます。それ以外の場合は、レクサーはそのまま続行します。 perlはexec自身ではありません。その結果、あなたはexecに別のインタプリタをしようとしたPerlずにシェバングでかなり奇妙なことを行うことができます

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

あなたのシンボリックリンクの例は、上記の条件をすべて満たしているので、なぜISNそこに無限ループがありますか?あなたは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が実際にリンクをexecませんが、それは名前でperlが含まれていないため、最後の条件は、もはや周りの2回目のループ端を満たしています。

+0

注:これはOPが 'perl/tmp/pscript'を使ってスクリプトを起動したことを前提としています。 '/ tmp/pscript'を使ってスクリプトを起動すると、その答えは少し異なります。 – ikegami

12

この機能のマニュアルは、perlrunにあります。

#!ラインが単語「perlの」も言葉「indir」、Perlインタプリタの代わりに実行された#!にちなんで名付けられたプログラムが含まれていない場合。これはやや奇妙ですが、#!のマシンでは、SHELLが/usr/bin/perlであることをプログラムに伝えることができるので、Perlはそのプログラムを正しいインタープリターにディスパッチします。

シェバングがperlまたはindirが含まれているのであれば、シェバングラインからインタプリタは実行されません。

Additionallyargv[0]perlが含まれていない場合、shebang行のインタープリタは実行されません。これはあなたの例の無限ループを防ぐものです。

その後、
  • カーネルがperl /tmp/pscriptを実行perl /tmp/pscript

    1. を使用して起動、
    2. perl/tmp/p /tmp/pscriptを実行します。
    3. argv[0]にはperlが含まれていないため、シバンラインはもはや意味のないものです。
  • カーネルが/tmp/p /tmp/pscriptを実行/tmp/pscript

    1. を使用して起動。
    2. argv[0]にはperlが含まれていないため、シバンラインはもはや意味のないものです。
+0

そして、5.24以降、単語「Perl6のは」Perl6のシェバングとプログラムがperl5のインタプリタによって実行された場合、それは再execのPerl6のことを意味、「パール」のために一致するとみなされていない、というよりもしてみてくださいそれ自体を実行します。 'perlrun'はこれを反映するように更新されていないようです。 – hobbs

+0

(実際にループを起こすことになっている場合は、perl6.24を 'perl6'としてシンボリックリンクすると、ループ例外条件*にはこの例外はありません。) – hobbs

+0

@hobbs、私がリンクしているのは5.24です。詳細はこちら、ThisSuitIsBlackNotの回答をご覧ください。私は質問の範囲に答えを制限していましたが、確かに他の "隠された"規則があります。 – ikegami

関連する問題