你看到的這裏是bash
和execve
的記錄的行爲(至少,它記錄上Linux和FreeBSD;我相信,其他系統也有類似的文件),並反映了argv[0]
構造的不同方式。
Bash(像任何其他shell)構造argv
從提供的命令行,在執行了各種擴展,根據需要resplit字等等之後。最終的結果是,當在鍵入
printargv
argv
被構造爲{ "printargv", NULL }
和當鍵入
to/printargv
argv
被構造爲{ "to/printargv", NULL }
。所以沒有什麼驚喜。
(在這兩種情況下,都出現過命令行參數,他們會出現在argv
開始在位置1)
但執行路徑分叉,這一點上。當命令行中的第一個單詞包含/時,則認爲它是文件名,無論是相對的還是絕對的。殼不做進一步處理;它簡單地使用提供的文件名作爲filename
參數和argv
陣列作爲其argv
參數構造的簡單號碼execve
。在這種情況下,argv[0]
正好對應於filename
但是,當命令沒有斜槓:
printargv
殼做了很多工作:
首先,它會檢查如果該名稱是用戶定義的shell函數。如果是這樣,它會執行它,$1...$n
取自argv
陣列已經構建。 ($0
仍然是腳本調用的argv[0]
)
然後,它檢查名稱是否是內置的bash命令。如果是這樣,它會執行它。內置函數如何與命令行參數進行交互不在這個答案的範圍之內,並且實際上並不是用戶可見的。
最後,它試圖通過搜索$PATH
的組件並查找可執行文件來查找與該命令對應的外部實用程序。如果它找到一個,它會調用execve
,給它一個它作爲filename
參數找到的路徑,但仍然使用由命令中的單詞組成的argv
數組。所以在這種情況下,filename
和argv[0]
做不是對應。
因此,在兩種情況下,殼結束調用execve
,提供了一個文件路徑(可能相對)作爲filename
參數和字分割命令作爲argv
參數。
如果指定的文件是可執行映像文件,沒有什麼可說的了,真的。圖像被加載到內存中,它的main
被提供的argv
矢量調用。 argv[0]
將是一個單詞或相對或絕對路徑,僅取決於最初輸入的內容。
但是,如果指定的文件是腳本,加載器將產生錯誤,execve
將檢查文件是否以shebang開頭(#!
)。 (自2008年以來的Posix,execve
也將嘗試運行該文件使用系統shell腳本,好像它有#!/bin/sh
的家當線。)
下面是關於Linux的execve
的文檔:
解釋型的腳本是具有執行啓用許可的文本文件,其第一行的形式爲:
#! interpreter [optional-arg]
的解釋必須是可執行文件的有效路徑名。如果調用execve的文件名參數()指定解釋型的腳本,然後解釋將與以下參數調用:
interpreter [optional-arg] filename arg...
其中arg...
是該系列的話指出,由argv
說法execve()
,開始argv[1]
。
注意,在上文中,filename
參數是filename
參數execve
。鑑於家當線#!/bin/bash
我們現在有兩種
/bin/bash to/printargv # If the original invocation was to/printargv
或
/bin/bash /path/to/printargv # If the original invocation was printargv
注意argv[0]
有效地消失了。
bash
然後在文件中運行腳本。在執行該腳本之前,它將$0
設置爲給定的文件名參數,在我們的示例中爲to/printargv
或/path/to/printargv
,並將$1...$n
設置爲其餘參數,這些參數是從原始命令行的命令行參數中複製的。
總之,如果你使用的文件名不帶斜槓調用命令:
如果調用使用帶斜槓的文件名的命令,在這兩種情況下,它會看到的argv [0]作爲文件名輸入號碼(這可能是相對的,但顯然會始終有一個斜槓)。另一方面,如果您通過顯式調用shell解釋器來調用腳本(bash printargv
),腳本將會看到$0
作爲鍵入的文件名,這不僅可能是相對的,也可能不會有斜槓。
所有這些意味着如果您知道調用您想要模仿的腳本的形式,只能「仔細地模仿argv [0]」。 (這也意味着腳本不應該依賴argv[0]
的值,但這是一個不同的主題。)
如果您正在爲單元測試執行此操作,則應該提供一個選項來指定要提供的值爲argv [ 0]。許多試圖分析$0
的shell腳本假定它是一個文件路徑。他們不應該這樣做,因爲它可能不是,但它就是這樣。如果你想抽出這些公用設施,你需要提供一些垃圾值,如$0
。否則,作爲默認的最佳選擇是提供腳本文件的路徑。
感謝您的回覆。 printargs.sh確實有一個shebang。我發佈了它的2行源代碼。 這仍然留下了問題的重要部分:什麼是準確模仿$ argv [0]與bash腳本的正確方法? –
@jason,是的,對不起,我被打斷了。我會在幾個小時內完成答案。 – rici
@jason:好的,重寫了答案;希望能幫助到你。我不認爲有一個「正確的方式」,因爲argv [0]可能是這個,或者可能是這樣,理想情況下,bash腳本也可以。所以如果你正在測試,你應該用$ 0的各種值測試腳本。如果你只是想給它一些合理的話,我的建議是使用完整的絕對文件名。 – rici