我可以使用可變內容作為 shebang 嗎?

我可以使用可變內容作為 shebang 嗎?

我有一個 shell 腳本,我想在其中添加一個 shebang。給定一個定義如下的變數:

SHEBANG="#!/bin/sh"

我的問題是我是否可以在另一個腳本中使用該變量,如下所示:

$SHEBANG
# other stuff...

答案1

不會。

  • 如果您出於某種原因想使用環境變數作為解釋器,您可以建立一個重新產生的「trampoline」可執行檔(不是腳本!)$SHEBANG "$@"。在這種情況下,您需要省略#!變數中的 ;#!僅當它實際上是文件的前兩個位元組時才有用。

  • 另一個選擇是利用事實上,沒有 shebang 行的腳本(通常)將作為 shell 腳本與sh呼叫 shell一起執行。如果您的 shebang 目標有一個與 shell 語法有效重疊的註解語法,您就可以使其運作。這種策略在 Lisp 解譯器中很常見,或者曾經很常見。在您的範例中,解釋器也是sh,這是不可行的。

  • 如果您可以依賴在場,您可以在該行上進一步推進bash:第一行是的腳本

    exec /bin/bash -c 'exec "$SHEBANG" <(tail -n +2 "$0")' "$0" "$@"
    

    適用於大多數口譯員; Bash 用作中間步驟,以便流程替代可以用來擁有tail為我們跳過第一行,這樣我們就不會陷入無限循環。一些解釋器要求文件是可找到的,並且他們不會接受這樣的管道。


值得考慮一下這是否真的是您想做的事情。除了任何安全問題之外,它並不是很有用:很少有腳本可以像這樣改變其解釋器,並且在可以的情況下,您幾乎肯定會使用更受限制的邏輯塊來更好地生成適合情況的正確邏輯區塊(可能是介於兩者之間的 shell 腳本,它以實際腳本的路徑作為參數來呼叫解釋器)。


* 不總是;在某些情況下,某些 shell 會自行讀取它,但它們仍然不會進行變數擴展。

答案2

我不知道這是否是您想要的用例,但是您有一件事做的是

#!/usr/bin/env python

所以你的腳本使用第一個pythonin而$PATH不是需要硬編碼/usr/bin/python,這可能在某些包含「好」版本的 python 的系統上運作良好。/usr/local/bin/opt

為什麼使用“#!/usr/bin/env NAME”而不是“#!/path/to/NAME”作為我的 shebang 更好?


這不會創建無限循環,因為 Python 解釋器(env在檔案上呼叫)只是將該#!行視為註解。這是設計的重點#!,因為許多語言都使用#註解字元。

為了擴展這一點,你可以寫一個多語言程式它最初在 下運行#!/bin/sh,但隨後找出實際使用的解釋器,並在同一腳本上呼叫它。

原來已經有具有多行 shebang 技巧的網頁對於許多語言,包括編譯語言(腳本將其自身的一部分提供給編譯器並運行輸出)。


手冊perlrun頁給了這個範例作為替代#!/usr/bin/env perl

    #!/bin/sh
    #! -*-perl-*-
    eval 'exec perl -x -wS $0 ${1+"$@"}'
        if 0;

    your perl script goes here

當作為/bin/sh腳本運行時,在您的腳本上eval運行perl -x -wS,並傳遞您的參數。

當 Perl 運行它時,由下一行eval的 控制,因此它永遠不會運行。if 0;與 不同sh,Perl 語句不以換行符號結束。

"$SHEBANG"您可以使用代替perl,甚至運行多個sh命令來選擇要使用的 perl 解釋器,從而使其變得更複雜。

答案3

我想這就是你想要的:

xb@dnxb:/tmp$ cat /tmp/hole.sh
#!/usr/bin/$shell_var
echo 1
readlink "/proc/$$/exe"
echo 2
function f { echo hello world; } 
echo 3 
xb@dnxb:/tmp$ chmod +x /tmp/hole.sh
xb@dnxb:/tmp$ sudo vi /usr/bin/\$shell_var 
xb@dnxb:/tmp$ cat /usr/bin/\$shell_var 
#!/bin/bash
/bin/dash -- "$@"
xb@dnxb:/tmp$ sudo chmod +x /usr/bin/\$shell_var
xb@dnxb:/tmp$ ./hole.sh
1
/bin/dash
2
./hole.sh: 5: ./hole.sh: function: not found
3
xb@dnxb:/tmp$ sudo vi /usr/bin/\$shell_var 
xb@dnxb:/tmp$ cat /usr/bin/\$shell_var 
#!/bin/bash
/bin/bash -- "$@"
xb@dnxb:/tmp$ ./hole.sh 
1
/bin/bash
2
3
xb@dnxb:/tmp$ 

解釋:

  1. 使用\$shell_varfile 作為“變數”來定義您想要的 shell。

  2. readlink "/proc/$$/exe"將列印當前外殼

  3. 由於破折號不支持function f { echo hello world; }句法,所以它產生了錯誤function: not found,但是將檔案中的 shell 更改為 bash\$shell_var將不會再出現錯誤。

  4. 完整的文件路徑(或相對路徑,如果 ./hole.sh 在 /tmp 中運行)將傳遞給$@\$shell_var文件,/tmp/hole.sh並將在\$shell_var.

相關內容