在 bash 中,通常time cmd
对多种类型的(s) 执行以下操作:cmd
$ time true
real 0m0.000s
user 0m0.000s
sys 0m0.000s
输出格式可以更改(甚至可以更改为带有 time -p 的 posix 格式):
$ TIMEFORMAT='real %R'; time true
real 0.000
但是 zsh 不报告简单命令的时间(也可以尝试time echo
):
% time true
将命令转换为管道会报告其他内容:
$ zsh -c 'time echo yes | cat'
yes
echo yes 0.00s user 0.00s system 26% cpu 0.001 total
cat 0.00s user 0.00s system 85% cpu 0.002 total
可以通过子 shell 强制 shell 给出时间输出(…)
:
$ zsh -c 'time ( true )'
( true; ) 0.00s user 0.00s system 26% cpu 0.005 total
但这不适用于{…}
,也不适用于以下内置函数for
:
$ zsh -c 'time { for i in $(seq 100); do ls; done >/dev/null; }'
zsh 的时间如何能够在没有子 shell 的情况下接受简单的命令。
或者,一个更简单的问题:
有没有办法编写在 ksh、bash、zsh 中使用 time 关键字运行的代码?
答案1
time
不对命令计时。 来自单一 Unix 规范的理由:
期限公用事业被使用,而不是命令,强调 shell 复合命令、管道、特殊内置命令等不能直接使用的事实。
这不锈钢time
还指出,结果特别的内置命令未定义,其结果用于除简单的命令(即在管道或命令分组上)未指定。
这是因为time
是不是不需要是特殊的 shell 语法,也不需要是内置命令。是否在第一次标准化时变化很大,现在也变化很大。
- 在 Almquist 和 (Heirloom) Bourne shell 中,
time
既不是保留字也不是内置命令。它是一个外部命令,因此不能应用于除简单的命令。time
BSD上的外部命令使用wait4()
库函数从内核返回的进程使用信息,如果要对shell内置命令和管道进行计时,则要求被计时的程序是shell。因此,诸如time bindkey
找不到要执行的实用程序之类的事情以及诸如time echo
对操作进行计时之类的事情外部的echo
命令而不是 shell 内置命令。 - 在 C shell 中,
time
是一个内置命令,不能应用于除简单的命令。time
通过查看库函数的结果来工作wait4()
,这需要一个子进程来等待。所以C shell的time
总是分叉一个子进程,即使对于其他内置命令也是如此。您会发现诸如此类的事情time bindkey -v
一无所获,因为它们是在子进程中运行的结果time
。 - 在 Korn 和 Bourne Again shell 中,
time
是 shell 语法中的保留字,可应用于管道。这些 shell 不使用wait4()
库函数返回的子进程使用信息,而是通过将命令调用与对 的调用括起来getrusage()
并进行减法来计算时间。 - 在 Z shell 中,
time
是 shell 语法中的保留字,可应用于管道。 Z shell 确实使用库函数从内核返回的进程使用信息wait4()
,但不会强制分叉内置命令。所以它没有报告任何内容当没有子进程被分叉时(就像内置命令的情况一样true
);但相反,喜欢time set -o vi
实际取得一些成就。
正如其基本原理所述,单一 Unix 规范措辞宽松,以允许所有不同的行为。它表明计时 shell 内置命令是一个问题。
答案2
虽然大多数 shell 支持对外部和内置命令进行计时,但 zsh 不支持对内置命令进行计时。
如果您需要获得时间结果,您可以致电
time /bin/true
或者向 zsh 人员发送错误报告。
随着新信息的出现,事情看起来有所不同。
time
计时复杂命令仅在shell 中为保留字的情况下才有效。
所以你有两个限制因素
shell 需要能够对内置命令进行计时
shell 需要实现
time
为增强 shell 语法的保留字
这将潜在的 shell 候选列表减少为:
bosh bash mksh ksh
对于内置命令,shell 需要知道如何测量自己的计时。
对于复杂的命令,shell需要time
在解释器内部实现。