簡體   English   中英

我應該使用帶有 Bash 腳本的 Shebang 嗎?

[英]Should I use a Shebang with Bash scripts?

我正在使用 Bash

$ echo $SHELL
/bin/bash

從大約一年前開始,我停止在我的 Bash 腳本中使用 Shebangs。 我可以從使用#!/bin/sh#!/bin/bash中受益嗎?

更新:在某些情況下,文件僅被視為帶有 Shebang 的腳本,例如

$ cat foo.sh
ls

$ cat bar.sh
#!/bin/sh
ls

$ file foo.sh bar.sh
foo.sh: ASCII text
bar.sh: POSIX shell script, ASCII text executable

在類 UNIX 系統上,您應該始終以 shebang 行開始腳本。 系統調用execve (負責啟動程序)依賴於具有可執行文件頭或 shebang 行的可執行文件。

來自 FreeBSD 的execve 手冊頁

 The execve() system call transforms the calling process into a new process. The new process is constructed from an ordinary file, whose name is pointed to by path, called the new process file. [...] This file is either an executable object file, or a file of data for an interpreter. [...] An interpreter file begins with a line of the form: #! interpreter [arg] When an interpreter file is execve'd, the system actually execve's the specified interpreter. If the optional arg is specified, it becomes the first argument to the interpreter, and the name of the originally execve'd file becomes the second argument

同樣來自Linux 手冊頁

execve() 執行文件名指向的程序。 文件名必須是二進制可執行文件,或以以下形式行開頭的腳本:

 #! interpreter [optional-arg]

事實上,如果一個文件的標題中沒有正確的“幻數”(如 ELF 標題或#! ),則execve失敗並出現 ENOEXEC 錯誤(再次來自 FreeBSD 的 execve 手冊頁):

[ENOEXEC] 新進程文件具有適當的訪問權限,但其標頭中的幻數無效。


如果文件具有可執行權限,但沒有 shebang 行但似乎是文本文件,則行為取決於您正在運行的 shell。

大多數 shell 似乎會啟動自己的新實例並將文件提供給它,見下文。

由於無法保證該腳本實際上是為該 shell 編寫的,因此這可能會成功,也可能會失敗。

tcsh(1)

 On systems which do not understand the `#!' script interpreter conven‐ tion the shell may be compiled to emulate it; see the version shell variable. If so, the shell checks the first line of the file to see if it is of the form `#!interpreter arg ...'. If it is, the shell starts interpreter with the given args and feeds the file to it on standard input.

來自 FreeBSD 的sh(1)

If the program is not a normal executable file (i.e., if it
     does not begin with the “magic number” whose ASCII representation is
     “#!”, resulting in an ENOEXEC return value from execve(2)) but appears to
     be a text file, the shell will run a new instance of sh to interpret it.

來自 bash(1):

 If this execution fails because the file is not in executable format, and the file is not a directory, it is assumed to be a shell script, a file containing shell commands. A subshell is spawned to execute it.

您不能總是依賴非標准程序(如 bash)的位置。 我在/usr/bin/usr/local/bin/opt/fsf/bin/opt/gnu/bin中看到過 bash 等等。

所以通常使用env是個好主意;

#!/usr/bin/env bash

如果您希望腳本可移植,請使用sh而不是bash

#!/bin/sh

雖然像 POSIX 這樣的標准不保證標准實用程序的絕對路徑,但大多數類 UNIX 系統似乎在/bin中有sh ,在/usr/bin中有env

腳本應始終以 shebang 行開頭。 如果腳本不是以此開頭的,那么它可能會被當前的 shell 執行。 但這意味着,如果使用您的腳本的人運行的 shell 與您不同,則該腳本的行為可能會有所不同。 此外,這意味着腳本不能直接從程序運行(例如 C exec()系統調用或find -exec ),它必須從 shell 運行。

您可能對發明#!的 Dennis M Ritchie ( dmr ) 的早期描述感興趣。

從 uucp 1980 年 1 月 10 日星期四 01:37:58

.>來自 dmr Thu Jan 10 04:25:49 1980 遠離研究

系統已更改,因此如果正在執行的文件以魔術字符 #! ,該行的其余部分被理解為執行文件的解釋器的名稱。 以前(實際上仍然是)shell 完成了大部分工作。 當文本文件的名稱作為命令輸入時,它會自動在具有可執行模式的文本文件上執行。 將設施放入系統可帶來以下好處。

1) 它使 shell 腳本更像真正的可執行文件,因為它們可以是 'exec' 的主題。

2) 如果您在此類命令運行時執行“ps”,則會顯示其真實名稱而不是“sh”。 同樣,會計是在真實姓名的基礎上進行的。

3)Shell腳本可以設置用戶ID。

4) 提供備用外殼更簡單; 例如,如果您喜歡 Berkeley csh,則毫無疑問使用哪個 shell 來解釋文件。

5)它將讓其他口譯員更順利地融入其中。

為了利用這個絕妙的機會,把

 #! /bin/sh

在你的 shell 腳本第一行的左邊距。 后空白! 沒關系。 使用完整的路徑名(不進行搜索)。 目前整行限制為 16 個字符,但此限制將提高。

希望這可以幫助

  • 如果您編寫bash腳本,即包含 bashisms 的不可移植腳本,您應該繼續使用#!/bin/bash shebang 以確保使用正確的解釋器。 您不應將 shebang 替換為#!/bin/sh ,因為 bash 將在 POSIX 模式下運行,因此您的某些腳本的行為可能會有所不同。

  • 如果您編寫可移植腳本,即僅使用 POSIX 實用程序及其支持的選項的腳本,您可能會繼續在您的系統上使用#!/bin/sh (即/bin/sh是 POSIX shell 的系統)。

  • 如果您編寫嚴格符合 POSIX 腳本以分發在各種平台上,並且您確定它們只會從符合 POSIX 的系統啟動,您可能並且可能應該刪除 POSIX 標准中所述的 shebang:

就目前而言,嚴格遵守的應用程序不得使用“#!” 作為文件的前兩個字符。

理由是 POSIX 標准不要求/bin/sh成為符合 POSIX 的外殼,因此沒有可移植的方式來指定其在 shebang 中的路徑。 在第三種情況下,為了能夠在無法運行 shebangless 仍可執行腳本的系統上使用“find -exec”語法,您可以簡單地在 find 命令本身中指定解釋器,例如:

find /tmp -name "*.foo" -exec sh -c 'myscript "$@"' sh {} + 

在這里,由於sh沒有指定路徑,因此將運行 POSIX shell。

標頭很有用,因為它指定了運行腳本時要使用的 shell。 例如, #!/bin/zsh會將 shell 更改為 zsh 而不是 bash,您可以在其中使用不同的命令。

例如,此頁面指定以下內容:

使用#!/bin/sh,UNIX 的大多數商業變體中的默認 Bourne shell,使腳本可移植到非 Linux 機器,盡管你犧牲了 Bash 特定的功能......

$SHELL 和 #!/bin/bash 或 #!/bin/sh 是不同的。

首先,#!/bin/sh 是大多數 Linux 系統上 /bin/bash 的符號鏈接(在 Ubuntu 上現在是 /bin/dash)

但是關於是從 /bin/sh 還是 /bin/bash 開始:

Bash 和 sh 是兩個不同的 shell。 基本上 bash 是 sh,具有更多功能和更好的語法。 大多數命令的工作方式相同,但它們不同。

假設如果您正在編寫 bash 腳本,請堅持使用 /bin/bash 而不是 /sh,因為可能會出現問題。

$SHELL 不一定反映當前運行的 shell。 相反,$SHELL 是用戶首選的 shell,它通常是 /etc/passwd 中設置的那個。 如果您在登錄后啟動不同的 shell,則不一定希望 $SHELL 與當前 shell 匹配。

例如,這是我的,但它也可能是 /root:/bin/dash 或 /root:/bin/sh,具體取決於您在 passwd 中輸入的 shell。 因此,為避免任何問題,請將 passwd 文件保存在 /bin/bash 中,然后使用 $SHELL 與 #!/bin/bash 無關緊要。

root@kali:~/Desktop# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash

資料來源: http ://shebang.mintern.net/bourne-is-not-bash-or-read-echo-and-backslash/ https://unix.stackexchange.com/questions/43499/difference-between-echo- shell-and-which-bash http://man.cx/sh http://man.cx/bash

除了其他人所說的之外,shebang 還可以在某些文本編輯器中啟用語法突出顯示,例如 vim。

TL;DR :總是在腳本中; 請不要在source 'd 腳本中

  • 永遠在你的父母身邊

    僅供參考:POSIX 兼容是#!/bin/bash ,而不是#!/bin/sh

    您想澄清這一點,以便沒有其他任何東西會覆蓋您的腳本所針對的解釋器。

    • 如果您的腳本是為 POSIX bash腳本編寫的,您不希望終端用戶使用zsh遇到麻煩。
    • 您不想在#!/bin/bash無法識別的#!/bin/sh中運行sourcesh終端中的某個人讓它破壞了腳本,因為它期待 simple/POSIX . 用於包含source 'd 文件
    • 您不希望例如zsh功能(在其他解釋器中不可用)進入您的bash代碼。 所以,把#!/bin/bash放在你所有的腳本頭中。 然后,您腳本中的任何zsh習慣都會被打破,因此您知道在推出之前將其刪除。

    這可能是最好的,尤其是符合 POSIX 的腳本不會在zsh之類的終端中中斷。

  • 不期望包含的source腳本

    僅供參考:在 BASH 腳本中獲取文本的 POSIX 兼容是. , 不是source

    您可以使用任何一種進行采購,但我會使用 POSIX。

    所有腳本的標准“shebanging”:

    父.sh

     #!/bin/bash echo "My script here" . sourced.sh # child/source script, below

    來源.sh

     echo "I am a sourced child script"

    但是,您可以這樣做...

    sourced.sh :(可選)

     #!/bin/bash echo "I am a sourced child script"

    在那里, #!/bin/bash "shebang" 將被忽略。 我使用它的主要原因是在我的文本編輯器中突出顯示語法。 但是,在“正確的”腳本世界中,預計您推出的source 'd 腳本將不包含 shebang。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM