什麼是最便攜的外殼,以及要遵循的相關最佳實踐?
幾個月來,我一直熱衷於 shell 腳本,發現我編寫的程式碼 (in
bash
) 在某些機器上不起作用。這是非常令人失望的。我意識到我應該學習最便攜的 shell 腳本。當然,這在開始時會有點痛苦,但我相信它最終會得到回報。我希望我的 shell 腳本幾乎可以在任何地方工作,包括 Linux 家族和 BSD 家族。(但我不在乎它們是否在 Windows 上執行。)
問題
- 最便攜的外殼是什麼?編輯:請省略這個問題
- 使用最便攜的外殼有哪些嚴重的缺點?編輯:請省略這個問題
- 如果我想編寫極其便攜的程式碼,我還應該注意什麼?例如,我應該使用和避免使用哪些核心工具以及哪些版本?
您的
bash
腳本應該可以在任何bash
安裝了 shell 的機器上執行,除非您使用bash
對於其他系統上的 shell 版本來說太新的功能,例如,嘗試使用名稱引用 (declare -n
)、關聯數組 (declare -A
) 或macOS 上的預設%(...)T
格式printf
(或許多其他不同事物中的任何一種) (這是古老的;在這種情況下,只需使用 Homebrewbash
安裝更新的版本)。bash
如果您的腳本使用在其他系統上不可用的外部工具,或者可能未實現的工具功能或以不同方式實現的工具,您的腳本也可能會失敗。POSIX 系統上最便攜的 shell 語言是
sh
shell。這在這裡描述:https ://pubs.opengroup.org/onlinepubs/9699919799/idx/shell.html
bash
shell(和其他)實現,sh
帶有擴展。一些 shell,比如fish
orzsh
,甚至根本沒有嘗試成為sh
shell(但zsh
通過 提供了一定程度的“sh
-emulation”--emulate sh
),而 shell likedash
確實試圖更純粹地符合 POSIXsh
標準(但仍然有一些擴展)。一般來說,與語法和內置功能相關的 shell 方面應該是“可移植的”,只要腳本總是由同一個 shell(和 shell 的版本,在某種程度上)執行,即使那個 shell 恰好是
fish
貝殼。這與 Python、Perl 和 Ruby 腳本的“可移植性”類型相同。然而,應該始終有一個sh
可用的 shell(通常安裝為/bin/sh
),它通常是bash
,dash
,或ksh
以某種形式的“兼容模式”執行。POSIX 系統上最便攜的實用程序是 POSIX 實用程序。這些在此處進行了描述:https ://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html
中的 GNU 實用程序
coreutils
實現了 POSIX 實用程序(正如使用者 schily在評論中指出的那樣,這並不意味著它們與 POSIX兼容),然後使用主要是為了方便的特性對其進行擴展。對於其他 Unix 系統上的相應實用程序也是如此。另請注意,coreutils
Linux 上的 GNU 包不包含 POSIX 指定的所有實用程序,find
並且所有 POSIX 實用程序等實用程序都單獨打包。sed``awk
只要您使用 POSIX 實用程序並使用它們的 POSIX 行為(在選項等方面),在使用 POSIX
sh
語法的腳本中,您很可能在大多數 Unix 系統中“大部分可移植”。但還要注意,非 POSIX 實用程序和 POSIX 實用程序的非 POSIX 擴展仍然相當可移植,因為它們通常被實現。常見的非 POSIX 實用程序的範例是pkill
、tar
和gzip
. 常見的 POSIX 實用程序的非 POSIX 擴展範例是謂詞-iname
,find
並且sed
通常可以使用.-E
您將通過自己測試(例如在虛擬機中)以及閱讀本網站上的問題和答案,了解哪些工具的實現中的哪些擴展、在哪些 Unices 上執行、以何種方式執行。例如,如何使用 sed -i(就地編輯)實現可移植性?
另請注意,在某些情況下,POSIX 標準會留下“未指定”行為,這意味著使用 POSIX 選項的兩個不同 Unix 系統上的相同實用程序可能會表現不同。這方面的一個例子可以在為什麼權限被拒絕時符號連結更新到具有權限的新目標時被拒絕?
嘗試編寫純 POSIX shell 程式碼的缺點是您錯過了一些真正有用的功能。我曾經嘗試
find
為該 GNU 的-readable
謂詞測試編寫 POSIX 等效測試,這並不容易,並且嘗試使用名稱來表示程序,ps
而grep
不是pkill
這個站點上的幾個太多問題的主題。同樣,試圖“保持 POSIX”,您將需要遠離真正有用的東西,例如perl
,並且您將無法以便攜方式完成任何管理任務(添加使用者、管理備份、在系統之間傳輸文件等)一般來說,我更喜歡一種務實的方法來完成工作,同時理解我的程式碼可能必須在以後修改以支持其他系統(如果它曾經在其他系統上使用過),而不是純粹的方法。這並不能阻止我編寫我知道的可移植性問題盡可能少的腳本(我不會到處使用不可移植的語義)。但這是我個人的看法。