2017-06-18 44 views
2

通過所謂的shebang線將腳本綁定到特定的解釋器是在操作系統上的衆所周知的練習。例如,如果執行了以下腳本(給定足夠的文件系統許可權),操作系統將啓動該腳本的文件名作爲其第一個參數的解釋器/bin/sh。隨後,shell將在腳本中執行跳過shebang行的命令,它將視爲註釋。通過shebang線連接口譯員是否便攜?

#! /bin/sh 

date -R 
echo hello world 

可能的輸出:

Sat, 01 Apr 2017 12:34:56 +0100 
hello world 

曾經相信的解釋器(在這個例子中/bin/sh必須是原生可執行文件,不能是一個腳本本身,反過來,將需要另一名口譯員啓動。

但是,我繼續嘗試下面的實驗。

使用保存爲/tmp/interpreter.py以下啞殼,...

#! /usr/bin/python3 

import sys 
import subprocess 

for script in sys.argv[1:]: 
    with open(script) as istr: 
     status = any(
      map(
       subprocess.call, 
       map(
        str.split, 
        filter(
         lambda s : s and not s.startswith('#'), 
         map(str.strip, istr) 
        ) 
       ) 
      ) 
     ) 
     if status: 
      sys.exit(status) 

...並保存爲/tmp/script.xyz下面的腳本,

#! /tmp/interpreter.py 

date -R 
echo hello world 

...我能夠(使這兩個文件執行後),以執行script.xyz

 
5gon12eder:/tmp> ls -l 
total 8 
-rwxr-x--- 1 5gon12eder 5gon12eder 493 Jun 19 01:01 interpreter.py 
-rwxr-x--- 1 5gon12eder 5gon12eder 70 Jun 19 01:02 script.xyz 
5gon12eder:/tmp> ./script.xyz 
Mon, 19 Jun 2017 01:07:19 +0200 
hello world 

這讓我感到驚訝。我甚至能夠通過另一個腳本啓動scrip.xyz

那麼,我問的是:

  • 是行爲,通過我的實驗觀察到便攜?
  • 實驗是否正確進行或者是否存在這種情況不起作用?不同的(類Unix的)操作系統如何?
  • 如果這樣運作的,這是真的,有一個本地可執行,並儘可能調用而言的解釋腳本之間沒有明顯的區別?

回答

1
  1. 見下文粗體文字:

    這種機制允許腳本可以用於幾乎任何環境 正常編譯的程序就可以了,包括作爲完整的系統方案, 甚至作爲口譯其他腳本。儘管如此,一些早期版本的內核支持將解釋器 指令的長度限制爲大約32個字符(其第一個 實現中只有16個字符),將無法將解釋器名稱與指令中的任何 參數分開,或有其他怪癖。另外,一些現代系統允許限制整個機制或禁用 (例如,許多系統上的腳本禁用了set-user-id支持, 已被禁用)。 - WP

  2. 而且從COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39這個輸出上的Ubuntu 17.04中, 特別是線#186-#189它告訴我們什麼作品上的Linux(即腳本可以解釋,多達四個層次深):

 
166: Interpreter scripts 
167-  An interpreter script is a text file that has execute permission 
168-  enabled and whose first line is of the form: 
169- 
170-   #! interpreter [optional-arg] 
171- 
172-  The interpreter must be a valid pathname for an executable file. 
173-  If the filename argument of execve() specifies an interpreter 
174-  script, then interpreter will be invoked with the following argu‐ 
175-  ments: 
176- 
177-   interpreter [optional-arg] filename arg... 
178- 
179-  where arg... is the series of words pointed to by the argv argu‐ 
180-  ment of execve(), starting at argv[1]. 
181- 
182-  For portable use, optional-arg should either be absent, or be 
183-  specified as a single word (i.e., it should not contain white 
184-  space); see NOTES below. 
185-
186-  Since Linux 2.6.28, the kernel permits the interpreter of a script 
187-  to itself be a script. This permission is recursive, up to a 
188-  limit of four recursions, so that the interpreter may be a script 
189-  which is interpreted by a script, and so on. 
-- 
343: Interpreter scripts 
344-  A maximum line length of 127 characters is allowed for the first 
345-  line in an interpreter scripts. 
346- 
347-  The semantics of the optional-arg argument of an interpreter 
348-  script vary across implementations. On Linux, the entire string 
349-  following the interpreter name is passed as a single argument to 
350-  the interpreter, and this string can include white space. How‐ 
351-  ever, behavior differs on some other systems. Some systems use 
352-  the first white space to terminate optional-arg. On some systems, 
353-  an interpreter script can have multiple arguments, and white spa‐ 
354-  ces in optional-arg are used to delimit the arguments. 
355- 
356-  Linux ignores the set-user-ID and set-group-ID bits on scripts. 
+0

謝謝,這篇文章實際上是我實驗的靈感。但由於它似乎與手冊頁mpez0引用的矛盾,我想知道這種說法是否便攜或甚至是真的。 – 5gon12eder

+0

感謝您的更新。這正是我所追求的信息。我係統上的手冊頁(Parabola GNU/Linux)沒有說明這一點。我冒昧地將您的答案的格式稍作修改,以使其更具可讀性。 – 5gon12eder

+0

@ 5gon12eder,這個重新格式化的降價*要好得多。 – agc

2

類Unix操作系統中的新可執行文件由系統調用execve(2)啓動。爲execve手冊頁包括:

Interpreter scripts 
    An interpreter script is a text file that has execute 
    permission enabled and whose first line is of the form: 

     #! interpreter [optional-arg] 

    The interpreter must be a valid pathname for an executable which 
    is not itself a script. If the filename argument of execve() 
    specifies an interpreter script, then interpreter will be invoked 
    with the following arguments: 

     interpreter [optional-arg] filename arg... 

    where arg... is the series of words pointed to by the argv 
    argument of execve(). 

    For portable use, optional-arg should either be absent, or be 
    specified as a single word (i.e., it should not contain white 
    space); see NOTES below. 

左右的時間內這些約束上(類似Unix的,最多一個字可選-ARG),是的,家當腳本是可移植的。閱讀手冊頁以獲取更多詳細信息,包括二進制可執行文件和腳本之間調用的其他差異。

+0

+1。您也可以在Linux內核源代碼中輕鬆找到它。我記得曾經有人回答過一個問題,那就是有些人希望'init'是一個python腳本或其他東西,這應該可以通過相同的邏輯來實現。任何人都敢指定一個文件作爲自己的解釋器? – mvds

+3

感謝您的快速回答,但這實際上讓我更加困惑:*「解釋器必須是可執行文件的有效路徑名**,它本身不是腳本**。」*這不代表我應該*不是*指定一個腳本作爲解釋器? – 5gon12eder

+0

@ mpez0,Re「_ ** ** man page_」:由於Unix類操作系統的文檔不同,請指定運行'man execv'的* OS *版本。 – agc