zsh 和 mksh 在哪里与 bash 不兼容?

Dan*_*096 13 bash zsh mksh

其他 POSIX 兼容的 shell 在多大程度上可以作为 bash 的合理替代品?它们不需要是真正的“插入式”替换,但足够接近以使用大多数脚本并通过一些修改支持其余脚本。

  1. 我想要显式的 bash 脚本 - initscripts、DHCP 客户端脚本等 - 以最少的修改工作

  2. 我希望我自己收集的更专业的 shell 脚本不需要太多修改

  3. 我想拥有字符串操作和内置正则表达式模式匹配等功能

我所知道的唯一认真的竞争者是 zsh 和 mksh。所以,对于在座的那些对他们中的一个或两个都很好的人:

  1. bash 有哪些 zsh 和 mksh 分别没有的特性?

  2. shell 与 bash 共享哪些功能,但使用不兼容的语法?

Gil*_*il' 20

我会坚持使用脚本功能。丰富的交互功能(命令行编辑、补全、提示等)往往千差万别,以完全不兼容的方式实现相似的效果。zsh 中有哪些功能而 bash 中缺少哪些功能,反之亦然?给出了一些关于交互式使用的提示。

最接近 bash 的是ATT ksh93mksh(Korn shell 和克隆)。Zsh 也有一个功能子集,但您需要在 ksh 仿真模式下运行它,而不是在 zsh 本机模式下运行。

我不会列出POSIX特性(在任何现代shshell 中都可用),也不会列出相对晦涩的特性,也不会列出上面提到的交互式使用特性。观察自 Debian wheezy 上的 bash 4.2、ksh 93u 和 mksh 40.9.20120630 起有效。

Shell 语法

引用

$'…'(带有反斜杠插值的文字字符串)在 ksh93 和 mksh 中可用。`$"..."(翻译后的字符串)是特定于 bash 的。

条件构造

Mksh 和 ksh93 必须;&case语句中失败,但不;;&测试后续案例。Mksh 有;|这个功能,最近的 mksh 允许;;&兼容性。

((…))算术表达式和[[ … ]]测试是 ksh 功能。一些条件运算符是不同的,请参阅下面的“条件表达式”。

协程

Ksh 和 bash 都有协进程,但它们的工作方式不同。

职能

mksh 和 ksh93function name {…}除了标准之外还支持函数定义的语法name () {…},但是function在 ksh 中使用会更改范围规则,因此请坚持name () …以保持兼容性。函数名中允许字符的规则各不相同;坚持使用字母数字和_.

支撑扩展

Ksh93 和 mksh 支持大括号扩展{foo,bar}{1..42}Ksh93支持数字范围,但 mksh 不支持。

参数扩展

ksh93的与mksh支持子提取${VAR:offset}${VAR:offset:length},但不区分折叠状${VAR^}${VAR,}等等。你可以做大小写转换typeset -l,并typeset -u在两者的bash和ksh。

它们支持替换为${VAR/PATTERN/STRING}${VAR/PATTERN//STRING}。STRING 的引用规则略有不同,因此避免在 STRING 中使用反斜杠(可能还有其他字符)(构建一个变量并${VAR/PATTERN/$REPLACEMENT}在替换包含引用字符时使用)。

数组扩展 ( ${ARRAY[KEY]}, "${ARRAY[@]}", ${#ARRAY[@]}, ${!ARRAY[@]}) 在 bash 中像在 ksh 中一样工作。

${!VAR}扩展到${OTHERVAR}时的值VAROTHERVAR(间接可变参考)是bash的特异性(KSH做了不同的用${!VAR})。要在 ksh 中获得这种双重扩展,您需要改用名称引用 ( typeset -n VAR=OTHERVAR; echo "$VAR")。${!PREFIX*}工作原理相同。

过程替换

进程替换<(…)并且>(…)在 ksh93 中受支持,但在 mksh 中不支持。

通配符模式

需要shopt -s extglob在 bash 中激活的 ksh 扩展 glob 模式在 ksh93 和 mksh 中始终可用。

Mksh 不支持像[[:alpha:]].

IO重定向

Bash 和 ksh93 定义了伪文件and ,但 mksh 没有。/dev/tcp/HOST/PORT/dev/udp/HOST/PORT

在脚本中的重定向中扩展通配符(如果该文件名是模式的唯一匹配,则var="*.txt"; echo hello >$a写入到a.txt)是 bash 特定的功能(其他 shell 永远不会在脚本中这样做)。

<<< here-strings 在 ksh 中像在 bash 中一样工作。

>&mksh 也支持重定向语法错误的快捷方式,但 ksh93 不支持。

条件表达式

[[ … ]] 双括号语法

ATT ksh93 和 mksh 都支持 ksh 中的双括号语法,就像在 bash 中一样。

文件操作符

Ksh93、mksh 和 bash 支持对 POSIX 的相同扩展,包括-a作为过时的同义词-e, -k(sticky -G), -O(owner by euid), -ef( owner by euid), (same file), -nt(newer than), -ot(older than)。

-N FILE (自上次阅读后修改)不受 mksh 支持。

Mksh 没有正则表达式匹配 operator =~。Ksh93 有这个运算符,它执行与 bash 相同的匹配,但没有等效的方法BASH_REMATCH来检索匹配的组。

字符串运算符

ksh93的和mksh支持相同的字符串比较操作<,并>为庆典还有==的代名词=。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 的。您可以使用.sh.fun,.sh.file.sh.linenoksh93获得类似的效果。在 mksh 中终于有LINENO.

declare, local,typeset

declare是 ksh 的 bash 特定名称typeset。使用typeset:它也适用于 bash。

Mksh 定义localtypeset. 在 ksh93 中,需要使用typeset(或定义别名)。

Mksh 没有关联数组(它们计划用于尚未发布的版本)。

我认为typeset -tksh 中没有与 bash 的(跟踪功能)完全相同的功能。

cd

Ksh93 没有-e.

echo

Ksh93 和 mksh 处理-e-n选项就像在 bash 中一样。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和通配符。这相当于mapfile -t lines </path/to/file

IFS=$'\n'; set -f
lines=($(</path/to/file))
unset IFS; set +f
Run Code Online (Sandbox Code Playgroud)

printf

printf非常相似。我认为 ksh93 支持所有 bash 的格式指令。mksh 不支持%q%(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 — 不要忽略通配符中的点文件

要模拟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 具有递归通配**/,使用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_IDKSH_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 没有。

Mksh 和 ksh93 具有RANDOM.