Bash 参考手册说
使用时间作为保留字允许对 shell 内置函数、shell 函数和管道进行计时。外部时间命令无法轻松地对这些进行计时。
但它只比较保留字
time
和外部命令time
,并没有解决问题:为什么 Bash 实现
time
为保留字,而不是内置命令?这能带来什么好处?
还有哪些其他保留字也可以作为(内置或外部)命令实现?与指挥同行相比,他们有什么优势? (试图弄清楚他们的优势是共同的还是各自特有的)
例如,
- 保留字
[[...]]
与内置命令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 command
合POSIX
规,因此整个行为ksh
都是POSIX
合规的。
BTW:[[
是shell 语法的reserved word
in ksh
to make 的一部分。[[ ... ]]
这避免了对模式使用 shell 转义(类似于case
构造)的需要,并且它允许运算符>
和<
用作算术运算符,而不是被识别为 I/O 重定向。