其他 POSIX 兼容的 shell 在多大程度上可以作为 bash 的合理替代品?它们不需要是真正的“插入式”替换,但足够接近以使用大多数脚本并通过一些修改支持其余脚本。
我想要显式的 bash 脚本 - initscripts、DHCP 客户端脚本等 - 以最少的修改工作
我希望我自己收集的更专业的 shell 脚本不需要太多修改
我想拥有字符串操作和内置正则表达式模式匹配等功能
我所知道的唯一认真的竞争者是 zsh 和 mksh。所以,对于在座的那些对他们中的一个或两个都很好的人:
bash 有哪些 zsh 和 mksh 分别没有的特性?
shell 与 bash 共享哪些功能,但使用不兼容的语法?
Gil*_*il' 20
我会坚持使用脚本功能。丰富的交互功能(命令行编辑、补全、提示等)往往千差万别,以完全不兼容的方式实现相似的效果。zsh 中有哪些功能而 bash 中缺少哪些功能,反之亦然?给出了一些关于交互式使用的提示。
最接近 bash 的是ATT ksh93或mksh(Korn shell 和克隆)。Zsh 也有一个功能子集,但您需要在 ksh 仿真模式下运行它,而不是在 zsh 本机模式下运行。
我不会列出POSIX特性(在任何现代sh
shell 中都可用),也不会列出相对晦涩的特性,也不会列出上面提到的交互式使用特性。观察自 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}
。{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}
时的值VAR
是OTHERVAR
(间接可变参考)是bash的特异性(KSH做了不同的用${!VAR}
)。要在 ksh 中获得这种双重扩展,您需要改用名称引用 ( typeset -n VAR=OTHERVAR; echo "$VAR"
)。${!PREFIX*}
工作原理相同。
进程替换<(…)
并且>(…)
在 ksh93 中受支持,但在 mksh 中不支持。
需要shopt -s extglob
在 bash 中激活的 ksh 扩展 glob 模式在 ksh93 和 mksh 中始终可用。
Mksh 不支持像[[:alpha:]]
.
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.lineno
ksh93获得类似的效果。在 mksh 中终于有LINENO
.
declare
, local
,typeset
declare
是 ksh 的 bash 特定名称typeset
。使用typeset
:它也适用于 bash。
Mksh 定义local
为typeset
. 在 ksh93 中,需要使用typeset
(或定义别名)。
Mksh 没有关联数组(它们计划用于尚未发布的版本)。
我认为typeset -t
ksh 中没有与 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 中,type
是whence -v
. 在 mksh 中,type -p
不打印可执行文件的路径,而是一个人类可读的消息;你需要whence -p COMMAND
改用。
shopt -s dotglob
— 不要忽略通配符中的点文件要模拟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 具有递归通配**/
,使用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
和KSH_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 没有。
Mksh 和 ksh93 具有RANDOM
.