为什么 Bash 将时间作为保留字而不是内置字来实现?

为什么 Bash 将时间作为保留字而不是内置字来实现?

Bash 参考手册说

使用时间作为保留字允许对 shell 内置函数、shell 函数和管道进行计时。外部时间命令无法轻松地对这些进行计时。

  1. 但它只比较保留字time和外部命令 time,并没有解决问题:

    为什么 Bash 实现time为保留字,而不是内置命令?

    这能带来什么好处?

  2. 还有哪些其他保留字也可以作为(内置或外部)命令实现?与指挥同行相比,他们有什么优势? (试图弄清楚他们的优势是共同的还是各自特有的)

    例如,

    • 保留字[[...]]与内置命令test[
    • 保留字select与内置命令read

答案1

您引用的文字已经解释了为什么time是关键字:

使用时间作为保留字允许对 shell 内置函数、shell 函数和管道进行计时。外部时间命令无法轻松地对这些进行计时。

如果time只是一个内置函数,它将无法正确测量管道所花费的时间,例如:

$ time sleep 2 | sleep 4

real    0m4.002s
user    0m0.000s
sys     0m0.002s

这里时间返回了 4 秒,这是整个管道所花费的时间。如果作为内置命令实现,shell 语法将只允许它返回 2 秒,因为命令,无论是否内置,都只能看到其参数,在特定情况下为sleep 2.

其他不能由内置函数实现的关键字是用于结构化结构的关键字,例如for, while, until, case, do, done, select, if, then, else, function.与 一样time,它们需要能够处理要解释的行,而不受简单命令边界的限制。

出于同样的原因,即能够访问要解析的整个 shell 输入,而不仅仅是这些关键字按原样实现的命令及其参数。例如,[命令参数会受到 shell 扩展和处理的影响,因此您无法*在测试中可靠地使用,并且>会被视为具有意外结果的重定向。

另一方面,[[正在更改 shell 行为,以便您可以使用它接受的任何语法,而不会受到 shell 的干扰。

以下是一些显示行为差异的示例:

$ if [ * = "*" ]; then echo ok; fi
bash: [: too many arguments
$ if [[ * = "*" ]]; then echo ok; fi
ok

$ 如果 [ 1 > 2 ];然后回声意外;否则回显预期;菲
意外
$ 如果 [ 1 -> 2 ];然后回声意外;否则回显预期;菲
预期的
$ 如果 [[ 1 > 2 ]];然后回声意外;否则回显预期;菲
预期的

请注意,不仅会if [ 1 > 2 ]返回意外结果,还会在当前目录中创建(或覆盖!)名为2.

答案2

在 bash 中成为保留字的一个重要原因time是它是ksh.

ksh当然,喜欢允许time做比外部命令或内置命令更多的事情,并且喜欢对一段管道进行计时。

顺便说一句:事实上,它time是 ksh 中的保留字,这将是一个 POSIX 合规性错误,但解析器会ksh检查下一个单词是否以 a 开头-,在这种情况下只调用外部命令/usr/bin/time。鉴于这POSIX需要您呼吁time -p commandPOSIX规,因此整个行为ksh都是POSIX合规的。

BTW:[[是shell 语法的reserved wordin kshto make 的一部分。[[ ... ]]这避免了对模式使用 shell 转义(类似于case构造)的需要,并且它允许运算符><用作算术运算符,而不是被识别为 I/O 重定向。

相关内容