繁体   English   中英

什么是 shell 脚本时间 **self**(真的)的优雅方式?

[英]What is an elegant way that a shell-script times **itself** (really)?

我有一个 bash 脚本,称之为 Exp,它执行计算实验,我想得到结果

time Exp

在脚本本身中:首先它需要始终完成(并且依靠键入“time Exp”是不够的——对于您(或用户)需要它的关键情况。它将被遗忘),其次脚本 Exp 本身需要将其存储在一个文件中。

由于 time-command 破坏了参数和输入/输出,编写包装脚本(称为“time Exp”)似乎使使用 Exp 的普通工作变得不可能。

但实际上所有需要的是访问 Exp 本身的数据,该数据只是按时间打印的通用记录(也可以通过 ps 访问),这就是为什么我要求一个“优雅”的解决方案,而不仅仅是首先存储不知何故,在 Exp 中的日期,最后,在退出之前。 计算差异。 但只是模拟时间命令在 Exp 中所做的事情。 我认为这在许多其他情况下会很有用。

由于 POSIX 定义了时间实用程序以将其结果写入标准错误,因此您必须注意的唯一技巧是有一个bash内置time的行为略有不同。

$ time sleep 1

real    0m1.004s
user    0m0.001s
sys     0m0.002s
$ time sleep 1 2>xyz

real    0m1.005s
user    0m0.001s
sys     0m0.003s
$ (time sleep 1) 2>xyz
$ cat xyz

real    0m1.005s
user    0m0.001s
sys     0m0.002s
$ /usr/bin/time sleep 1 2>xyz
$ cat xyz
        1.00 real         0.00 user         0.00 sys
$ 

在 MacOS X 10.7 上显示的测试。 请注意time命令的内置版本和外部版本之间 output 格式的差异。 另请注意,在子shell格式中,内置time是正常重定向的,但是在简单的情况下,在内置time之后重定向output不会将output发送到标准错误的Z65E8800B5C68A6888888888888B的Z65E8800B5C6800AAD8的Z65E8800B5C6800AAD8相同的地方去。

因此,这些观察结果使您可以编写优雅的脚本。 可能最简单的方法是将现有脚本包装为 function,然后通过内置time调用该 function。

原始脚本

# This is what was in the Exp script before.
# It echoes its name and its arguments to both stdout and stderr
echo "Exp $*"
echo "Exp $*" 1>&2

修改后的脚本

log=./Exp.log

Exp()
{
    # This is what was in the Exp script before.
    # It echoes its name and its arguments to both stdout and stderr
    echo "Exp $*"
    echo "Exp $*" 1>&2
}

(time Exp "$@") 2>> $log

Note the careful use of "$@" in the invocation of the Exp function to preserve the separate arguments passed on the command line, and the equally deliberate use of $* inside the function (which loses the separate arguments, but is only for illustrative目的)。

可能的问题

唯一的问题是来自原始命令的错误 output 也与计时信息进入相同的日志文件。 这可以解决,但涉及棘手的多次重定向,这些重定向更容易混淆而不是帮助。 但是,为了记录,这很好用:

log=./Exp.log

Exp()
{
    # This is what was in the Exp script before.
    # It echoes its name and its arguments to both stdout and stderr
    echo "Exp $*"
    echo "Exp $*" 1>&2
}

exec 3>&2

(time Exp "$@" 2>&3 ) 2>> $log

您可以将以下内容添加为脚本的第一行:

test -z "$TIMED" && TIMED=yes exec time $0 $@

如果在环境中设置了 TIMED,这将不会运行时间,因此如果需要,它可以为您提供一种抑制时间的方法。

上述两种解决方案调用时间命令。 我怀疑即使是@Jonathan Leffler 精心制作的脚本在功能上也确实等同于原始脚本:它似乎关注 output 到标准 output 和标准错误,但它的行为方式是 w.Z4B43Z.9AEE35624CD2B318 需要测试的符号链接(这不会那么简单——关于路径有很多微妙之处,尤其是在包含链接时)。 我认为 w.r.t。 讨厌的引用业务它肯定会改变原始脚本的语义,使得需要在参数中多添加一个引用层(例如,如果脚本远程运行,并且需要有引号)。

在处理路径和符号链接和引用这两个问题上,我们过去遇到了很多麻烦,而且这些错误很难发现:我们编写的脚本通常使用来自许多数学/计算机科学包的复杂脚本,实际上,必须处理数百个特别安装的包,每个包都有自己奇怪的特点,因此我们希望尽可能避免增加进一步的复杂性。

我在@Arne 的帮助下找到的解决方案更简单; 请参阅如何将 S-output-modifier 与 Unix/Linux 命令 ps 一起使用?

只需添加一行

ps p $$ k time S | tail -n 1 | tr -s '[:space:]' | cut -d ' ' -f 4 > log-file

当想要将(总)处理时间存储在日志文件中时到脚本。 不知道时间命令从哪里得到挂钟和系统时间,但对于挂钟,也许需要做时间减法; 并且不知道系统时间,但它必须在某个地方。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM