Shell 在所有if语句中,`[`命令之前使用的命令'builtin'
我在整个Shell 在所有if语句中,`[`命令之前使用的命令'builtin',shell,built-in,shunit2,Shell,Built In,Shunit2,我在整个shunit2中都看到了这一点,它的目标是在旧的Bourne风格的shell脚本中实现最大的可移植性(参见源代码): [难道不是所有伯恩风格外壳中的特殊内置物吗?(即ash/bin/bash/bin/dash/bin/ksh/bin/mksh/bin/pdksh/bin/zsh/usr/xpg4/bin/sh/bin/sh/sbin/sh) 如果shell中存在If-builtin,那么为什么需要编写If-builtin[…];然后?它就在脚本中每个If语句之前 更新: @triplee
shunit2
中都看到了这一点,它的目标是在旧的Bourne风格的shell脚本中实现最大的可移植性(参见源代码):
[
难道不是所有伯恩风格外壳中的特殊内置物吗?(即ash/bin/bash/bin/dash/bin/ksh/bin/mksh/bin/pdksh/bin/zsh/usr/xpg4/bin/sh/bin/sh/sbin/sh
)
如果shell中存在If-builtin
,那么为什么需要编写If-builtin[…];然后?它就在脚本中每个If语句之前
更新:
@tripleee在下面给出了正确的答案:[
可能是别名。为了子孙后代,我将POSIX外壳的评估顺序放在这里:
从包含1个或多个命令的标准输入中收集管道(称为“管道”)之间的每一行
将管道分解为命令
为管道设置I/O
对于每个命令
(a) 将命令拆分为令牌
(b) 如果第一个标记是关键字(不带引号或反斜杠),并且
是开头关键字(例如,如果
,{
,或(
),则
i、 在内部设置复合命令
ii.读取下一个命令并继续,直到复合命令关闭
(c)对照命令列表检查每个命令的第一个标记
别名,如果找到,则替换别名并返回步骤(a)
(d) 如果需要,对$HOME
执行波浪线替换(即替换~
)
~
当前)
(e) 执行变量替换(例如,$variable
)
(f) 执行命令替换(即$()
)
(g) 执行算术替换(即$(())
)
(h) 使用$IFS
分割步骤(e)
到
(g)
进入更多令牌
(i) 执行文件通配符扩展(即扩展*
,?
,和
[…]
对)
(j)搜索作为二进制文件路径命令的令牌
使用搜索顺序特殊内置-->函数-->常规内置-->$PATH
(k) 设置I/O重定向后运行命令
我忘了步骤(c)发生在步骤(j)之前因为用户可以用别名或函数来隐藏它,而使用内置的可以绕过这些,但不能完全移植到旧的shell。啊!我忘记了别名!我要用POSIX shell评估顺序更新我的问题。谢谢!我不相信[
是一个特殊的内置函数——我70%确定它只是一个普通的内置函数。(检查POSIX规范——这些特殊的内置函数都有一个指向“特殊内置函数”定义的链接,请参见另一节;它不用于测试。@CharlesDuffy在我列出的每一个Bourne shell上(至少在其最新版本中),运行type[
和type test
产生[是一个shell内置的和test是一个shell内置的,并运行command-v[
和command-v test
每个返回[
和分别测试
,表明它们不是作为常规内置的/usr/bin/
。因此,据我所知,它们是特殊的内置的。/usr/bin
中的存在确实离题了——一些操作系统有一个/usr/bin/exit
,一个/usr/bin/cd
,等等。尽管有这样的实用性除非作为特殊内置实现,否则es在客观上是无用的。常规内置仍然是内部shell实现;内置实现在/usr/bin
中不是可执行的。至于命令-v
和类型的演示,这些演示了内置性,但不是特殊内置性。RegULA内置仍然内置在shell本身中,尽管操作系统也可以提供一个外部版本,作为可执行文件与shell内置版本一起调用。
# Determine if `builtin` command exists.
__SHUNIT_BUILTIN='builtin'
# shellcheck disable=2039
if ! ("${__SHUNIT_BUILTIN}" echo 123 >/dev/null 2>&1); then
__SHUNIT_BUILTIN=''
fi
# Some more code ...
# ...and now a check
if ${__SHUNIT_BUILTIN} [ ... ]; then