zsh 和 mksh 與 bash 不兼容的地方在哪裡?
其他 POSIX 兼容的 shell 在多大程度上可以作為 bash 的合理替代品?它們不需要是真正的“插入式”替代品,但足以與大多數腳本一起使用並通過一些修改支持其餘腳本。
- 我想要顯式的 bash 腳本 - initscripts、DHCP 客戶端腳本等 - 只需最少的修改即可工作
- 我希望我自己收集的更專業的 shell 腳本不需要太多修改
- 我想要字元串操作和內置正則表達式模式匹配等功能
我所知道的唯一真正的競爭者是 zsh 和 mksh。所以,對於那些對其中一個或兩個都很好的人來說:
- bash 有哪些 zsh 和 mksh 分別沒有的功能?
- shell 與 bash 共享哪些功能,但使用不兼容的語法?
我會堅持腳本功能。豐富的互動功能(命令行編輯、補全、提示等)往往大相徑庭,以完全不兼容的方式實現相似的效果。zsh 中有哪些功能,而 bash 缺少哪些功能,反之亦然?給出了一些關於互動式使用的建議。
最接近 bash 的是ATT ksh93或mksh(Korn shell 和複製)。Zsh 也有一部分功能,但您需要在 ksh 仿真模式下執行它,而不是在 zsh 本機模式下執行。
我不會列出POSIX功能(在任何現代 shell 中都可用
sh
),也不會列出相對晦澀的功能,也不會列出上面提到的用於互動使用的功能。觀察結果在 Debian wheezy 上發現的 bash 4.2、ksh 93u 和 mksh 40.9.20120630 有效。外殼語法
報價
$'…'
(帶有反斜杠插值的文字字元串)在 ksh93 和 mksh 中可用。`$"…" (翻譯後的字元串)是 bash 特有的。條件構造
mksh 和 ksh93 必須
;&
在case
語句中通過,但不;;&
測試後續情況。Mksh;|
可以做到這一點,並且最近的 mksh 允許;;&
兼容性。
((…))
算術表達式和[[ … ]]
測試是 ksh 功能。一些條件運算符是不同的,請參閱下面的“條件表達式”。協同程序
Ksh 和 bash 都有協同程序,但它們的工作方式不同。
職能
mksh 和 ksh93
function name {…}
除了標準之外還支持函式定義的語法name () {…}
,但是function
在 ksh 中使用會改變作用域規則,所以要堅持name () …
保持兼容性。函式名稱中允許使用的字元的規則各不相同;堅持使用字母數字和_
.大括號擴展
Ksh93 和 mksh 支持大括號擴展
{foo,bar}
。Ksh93支持數字範圍{1..42}
,但 mksh 不支持。參數擴展
Ksh93 和 mksh 支持使用
${VAR:offset}
and提取子字元串${VAR:offset:length}
,但不支持大小寫折疊,如${VAR^}
,${VAR,}
等。您可以在 bash 和 ksh 中使用typeset -l
and進行大小寫轉換。typeset -u
${VAR/PATTERN/STRING}
他們支持用or替換${VAR/PATTERN//STRING}
。STRING 的引用規則略有不同,因此請避免在 STRING 中使用反斜杠(可能還有其他字元)(建構一個變數並${VAR/PATTERN/$REPLACEMENT}
在替換包含引用字元時使用)。數組擴展 (
${ARRAY[KEY]}
,"${ARRAY[@]}"
,${#ARRAY[@]}
,${!ARRAY[@]}
) 在 bash 中與在 ksh 中一樣工作。
${!VAR}
擴展到is (間接變數引用)${OTHERVAR}
的值是特定於 bash 的(ksh 與 做不同的事情)。要在 ksh 中獲得這種雙重擴展,您需要改用名稱引用 ( )。工作相同。VAR``OTHERVAR``${!VAR}``typeset -n VAR=OTHERVAR; echo "$VAR"``${!PREFIX*}
流程替代
程序替換
<(…)
,>(…)
在 ksh93 中受支持,但在 mksh 中不支持。萬用字元模式
需要在 bash 中啟動的 ksh 擴展 glob 模式
shopt -s extglob
在 ksh93 和 mksh 中始終可用。Mksh 不支持像
[[:alpha:]]
.IO 重定向
Bash 和 ksh93 定義了偽文件和,但 mksh 沒有。
/dev/tcp/*HOST*/*PORT*``/dev/udp/*HOST*/*PORT*
在腳本中的重定向中擴展萬用字元(如果該文件名是該模式的唯一匹配項,則
var="*.txt"; echo hello >$a
寫入該文件名)是 bash 特定的功能(其他 shell 從不在腳本中這樣做)。a.txt
<<<
here-strings 像在 bash 中一樣在 ksh 中工作。
>&
mksh 也支持重定向語法錯誤的快捷方式,但 ksh93 不支持。條件表達式
[[ … ]]
雙括號語法ATT ksh93 和 mksh 都支持來自 ksh 的雙括號語法,就像在 bash 中一樣。
文件運算符
Ksh93、mksh 和 bash 支持對 POSIX 的相同擴展,包括
-a
作為過時的同義詞-e
,-k
(sticky),-G
(由 egid 擁有),-O
(由 euid 擁有),-ef
(same file),-nt
(newer than),-ot
(older than)。
-N FILE
(自上次閱讀後修改)不受 mksh 支持。Mksh 沒有正則表達式匹配運算符
=~
。Ksh93 有這個運算符,它執行與 bash 中相同的匹配,但沒有等效的BASH_REMATCH
來檢索匹配的組。字元串運算符
Ksh93 和 mksh 支持相同的字元串比較運算符
<
和>
bash 以及 . 的==
同義詞=
。Mksh 不使用語言環境設置來確定字典順序,它將字元串作為字節字元串進行比較。其他運營商
-v VAR
測試是否定義了變數是特定於 bash 的。在任何 POSIX shell 中,您都可以使用[ -z "${VAR+1}" ]
.內置
alias
別名中允許的字元集在所有 shell 中都不相同。我認為這與函式相同(見上文)。
builtin
Ksh93 有一個名為
builtin
的內置命令,但它不會將名稱作為內置命令執行。用於command
繞過別名和函式;如果存在,這將呼叫內置命令,否則呼叫外部命令(您可以使用 避免這種情況PATH= command error_out_if_this_is_not_a_builtin
)。
caller
這是特定於 bash 的。您可以在 ksh93 中使用
.sh.fun
,.sh.file
和獲得類似的效果。.sh.lineno
在 mksh 中,終於有了LINENO
.
declare
,local
,typeset
declare
是 ksh 的 bash 特定名稱typeset
。使用typeset
:它也適用於 bash。Mksh 定義
local
為typeset
. 在 ksh93 中,您需要使用typeset
(或定義別名)。Mksh 沒有關聯數組(它們計劃用於尚未發布的版本)。
我認為 ksh 中沒有與 bash 的
typeset -t
(跟踪功能)完全等效的功能。
cd
Ksh93 沒有
-e
。
echo
Ksh93 和 mksh像在 bash 中一樣處理
-e
和選項。-n
mksh 也明白-E
,ksh93 不把它當作一個選項。反斜杠擴展在 ksh93 中預設關閉,在 mksh 中預設打開。
enable
Ksh 沒有提供禁用內置命令的方法。為避免使用內置命令,請查找外部命令的路徑並顯式呼叫它。
exec
Ksh93 有
-a
但沒有-l
。Mksh 兩者都沒有。
export
ksh93 和 mksh 都沒有
export -n
. 改用typeset +x foo
它,它適用於 bash 和 ksh。Ksh 不會通過環境導出函式。
let
let
在 bash 和 ksh 中是一樣的。
mapfile
,readarray
這是特定於 bash 的功能。您可以使用
while read
循環或命令替換來讀取文件並將其拆分為行數組。照顧IFS
和 globbing。這是等效的mapfile -t lines </path/to/file
:IFS=$'\n'; set -f lines=($(</path/to/file)) unset IFS; set +f
printf
printf
非常相似。我認為 ksh93 支持所有 bash 的格式指令。mksh 不支持%q
or%(DATE_FORMAT)T
; 在某些安裝中,printf
它不是內置的 mksh 而是呼叫外部命令。
printf -v VAR
是特定於 bash 的,ksh 總是列印到標準輸出。
read
有幾個選項是特定於 bash 的,包括所有關於 readline 的選項。選項
-r
,-d
,-n
,-N
,-t
,-u
在 bash、ksh93 和 mksh 中是相同的。
readonly
您可以使用相同的語法在 Ksh93 和 mksh 中將變數聲明為只讀。如果變數是一個數組,你需要先給它賦值,然後用
readonly VAR
. 函式不能在 ksh 中設為只讀。
set
,shopt
set
和的所有選項set -o
都是 POSIX 或 ksh 功能。
shopt
是特定於 bash 的。無論如何,許多選項都涉及互動式使用。有關某些選項啟用的通配和其他功能的影響,請參閱下面的“選項”部分。
source
這個變體也
.
存在於 ksh 中。在 bash 和 mksh 中,在 .source
之後搜尋目前目錄PATH
,但在 ksh93 中,它與.
.
trap
DEBUG
偽信號未在 mksh 中實現。在 ksh93 中,它以不同的方式上報資訊,詳見手冊。
type
在 ksh 中,
type
是whence -v
. 在 mksh 中,type -p
不列印執行檔的路徑,而是一條人類可讀的消息;你需要whence -p COMMAND
改用。選項
shopt -s dotglob
— 不要忽略 globbing 中的點文件要模擬
dotglob
ksh93 中的選項,您可以設置FIGNORE='@(.|..)'
. 我認為 mksh 中沒有這樣的東西。
shopt -s extglob
— ksh 擴展 glob 模式該
extglob
選項在 ksh 中始終有效。
shopt -s failglob
— 如果 glob 模式不匹配,則會出錯我認為這在 mksh 或 ksh93 中都不存在。它在 zsh 中執行(預設行為,除非設置
null_glob
或csh_null_glob
設置)。
shopt -s globstar
—**/
遞歸萬用字元Ksh93 具有遞歸 globbing
**/
,啟用set -G
. Mksh 沒有遞歸萬用字元。
shopt -s lastpipe
— 在父 shell 中執行管道的最後一條命令Ksh93 總是在父 shell 中執行管道的最後一個命令,這在 bash 中需要設置
lastpipe
選項。Mksh 總是在子shell 中執行管道的最後一個命令。
shopt -s nocaseglob
,shopt -s nocasematch
— 不區分大小寫的模式Mksh 沒有不區分大小寫的模式匹配。Ksh93 逐個模式地支持它:在模式前加上
~(i)
.
shopt -s nullglob
— 將不匹配文件的模式擴展為空列表Mksh 沒有這個。Ksh93 逐個模式地支持它:在模式前加上
~(N)
.變數
顯然大多數
BASH_xxx
變數在 ksh 中都不存在。$BASHPID
可以用昂貴但便攜的 模擬sh -c 'echo $PPID'
,並且最近已添加到 mksh。BASH_LINE
在.sh.lineno
ksh93 和LINENO
mksh 中。BASH_SUBSHELL
在.sh.subshell
ksh93 中。Mksh 和 ksh93 都在
ENV
它們啟動時獲取給定的文件。
EUID
並且UID
在 ksh93 中不存在。Mksh 稱它們為USER_ID
andKSH_UID
; 它沒有GROUPS
。
FUNCNAME
並且FUNCNEST
不存在於 ksh 中。Ksh93 有.sh.fun
和.sh.level
.function foo { …; }
用(沒有括號!)聲明的函式在$0
.
GLOBIGNORE
存在於 ksh93 但名稱和語法不同:它被稱為FIGNORE
,它是一個單一的模式,而不是一個冒號分隔的列表。使用@(…|…)
模式。KshFIGNORE
包含 bash,但語法完全不同。Ksh93 和 mksh 沒有類似
HOSTTYPE
,MACHTYPE
和OSTYPE
. 也不SHELLOPTS
或TIMEFORMAT
。Mksh 有
PIPESTATUS
,但 ksh93 沒有。Thx 和 ksh93 有
RANDOM
.