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

时间:2011-08-14 12:04:58

标签: bash benchmarking

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

time Exp

在脚本本身内:首先需要始终完成(并依赖于输入“time Exp”) 是不够的 - 对于您(或用户!!)需要它的关键情况,它将是 忘记了,第二个脚本Exp本身需要将它存储在一个文件中。

编写一个包装器脚本(调用“time Exp”)似乎可以正常使用 由于时间命令破坏了参数和输入/输出,因此无法实现。

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

3 个答案:

答案 0 :(得分:7)

由于POSIX定义time实用程序以将其结果写入标准错误,因此您必须注意的唯一技巧是存在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命令的内置和外部版本之间输出格式的差异。另请注意,在子shell格式中,内置time被正常重定向,但在简单的情况下,在内置time之后重定向输出不会将输出发送到同一个将标准错误的其余部分放在哪里。

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

原始脚本

# 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

请注意在Exp函数的调用中谨慎使用"$@"来保留在命令行上传递的单独参数,以及在函数内同样有意使用$*(它丢失了单独的参数,但仅用于说明目的。)

可能的问题

唯一的问题是原始命令的错误输出也与定时信息一起发送到同一个日志文件。这可以解决,但涉及tricky multiple redirections更容易混淆而不是帮助。但是,为了记录,这很好用:

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

答案 1 :(得分:1)

您只需添加以下内容作为脚本的第一行:

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

如果在环境中设置了TIMED,则不会运行时间,所以 如果你愿意,它会为你提供一种抑制时间的方法。

答案 2 :(得分:1)

以上两个解决方案调用time-command。我怀疑即使是非常 由@Jonathan Leffler精心设计的一个与原始剧本在功能上完全相同: 它似乎关注输出到标准输出和标准错误,但如何 它表现得很好。需要测试的符号链接(这不会那么简单--- 关于路径有许多细微之处,特别是在包含链接时)。 我认为w.r.t.令人讨厌的引用业务肯定会改变语义 对于原始脚本,需要在参数中添加一个引用层(例如,如果脚本远程运行,并且需要使用引号)。

有了这两个问题,处理路径,符号链接和引用,我们就有了 过去很麻烦,而且这些错误很难抓住:常常是 我们编写的脚本使用来自许多数学/计算机科学包的复杂的其他脚本,其中必须处理数百个特别安装的包, 每个都有自己独特的特色,所以我们希望尽可能避免 进一步增加并发症。

我在@Arne的帮助下找到的解决方案更简单;看到 How to use the S-output-modifier with Unix/Linux command ps?

只需要添加一行

ps p $$ k time S | tail -n 1 | tr -s '[:space:]' | cut -d ' ' -f 4 > log-file
当想要将(总)处理时间存储在日志文件中时,

到脚本。 不知道time-command在哪里获得挂钟和系统时间,但是 对于挂钟,或许需要减去时间;而且不知道 关于系统时间,但它必须在某个地方。