Bash

zsh 和 mksh 與 bash 不兼容的地方在哪裡?

  • September 12, 2019

其他 POSIX 兼容的 shell 在多大程度上可以作為 bash 的合理替代品?它們不需要是真正的“插入式”替代品,但足以與大多數腳本一起使用並通過一些修改支持其餘腳本。

  1. 我想要顯式的 bash 腳本 - initscripts、DHCP 客戶端腳本等 - 只需最少的修改即可工作
  2. 我希望我自己收集的更專業的 shell 腳本不需要太多修改
  3. 我想要字元串操作和內置正則表達式模式匹配等功能

我所知道的唯一真正的競爭者是 zsh 和 mksh。所以,對於那些對其中一個或兩個都很好的人來說:

  1. bash 有哪些 zsh 和 mksh 分別沒有的功能?
  2. shell 與 bash 共享哪些功能,但使用不兼容的語法?

我會堅持腳本功能。豐富的互動功能(命令行編輯、補全、提示等)往往大相徑庭,以完全不兼容的方式實現相似的效果。zsh 中有哪些功能,而 bash 缺少哪些功能,反之亦然?給出了一些關於互動式使用的建議。

最接近 bash 的是ATT ksh93mksh(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 和 ksh93function 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 -land進行大小寫轉換。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 定義localtypeset. 在 ksh93 中,您需要使用typeset(或定義別名)。

Mksh 沒有關聯數組(它們計劃用於尚未發布的版本)。

我認為 ksh 中沒有與 bash 的typeset -t(跟踪功能)完全等效的功能。

cd

Ksh93 沒有-e

echo

Ksh93 和 mksh像在 bash 中一樣處理-e和選項。-nmksh 也明白-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 不支持%qor %(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 中,typewhence -v. 在 mksh 中,type -p不列印執行檔的路徑,而是一條人類可讀的消息;你需要whence -p COMMAND改用。

選項

shopt -s dotglob— 不要忽略 globbing 中的點文件

要模擬dotglobksh93 中的選項,您可以設置FIGNORE='@(.|..)'. 我認為 mksh 中沒有這樣的東西。

shopt -s extglob— ksh 擴展 glob 模式

extglob選項在 ksh 中始終有效。

shopt -s failglob— 如果 glob 模式不匹配,則會出錯

我認為這在 mksh 或 ksh93 中都不存在。它在 zsh 中執行(預設行為,除非設置null_globcsh_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.linenoksh93 和LINENOmksh 中。BASH_SUBSHELL.sh.subshellksh93 中。

Mksh 和 ksh93 都在ENV它們啟動時獲取給定的文件。

EUID並且UID在 ksh93 中不存在。Mksh 稱它們為USER_IDand KSH_UID; 它沒有GROUPS

FUNCNAME並且FUNCNEST不存在於 ksh 中。Ksh93 有.sh.fun.sh.level. function foo { …; }用(沒有括號!)聲明的函式在$0.

GLOBIGNORE存在於 ksh93 但名稱和語法不同:它被稱為FIGNORE,它是一個單一的模式,而不是一個冒號分隔的列表。使用@(…|…)模式。KshFIGNORE包含 bash,但語法完全不同。

Ksh93 和 mksh 沒有類似HOSTTYPE,MACHTYPEOSTYPE. 也不SHELLOPTSTIMEFORMAT

Mksh 有PIPESTATUS,但 ksh93 沒有。

Thx 和 ksh93 有RANDOM.

引用自:https://unix.stackexchange.com/questions/158896