我有几种不同的算法,我需要对其进行原型设计。
所以我制作了原型程序和脚本。调用的脚本time.sh
看起来像这样
echo "Timing algorithm1:"
time algo1 >dev/null
echo "Timing algorithm2:"
time algo2 >dev/null
echo "Timing algorithm3:"
time algo3 >dev/null
...
现在为了简单起见,替换ls
为algo1
...(我不想为每个算法发布代码,强迫人们编译它...)
echo " Timing ls"
time ls 2>&1 > /dev/null
叫它time_ls.sh
然后我
sh time_ls.sh > ls_sh.meas
无论我做什么,无论我在脚本或命令行中放置什么重定向,我都会得到两个结果之一。我要么在终端中得到 echo 的输出,即“Timing ls”,要么ls_sh.meas
得到相反的定时数据。
这就像 stdout 和 stderr 不想聚集在一起并创建一个婴儿数据文件。
任何人都可以解释这种奇怪的行为,并建议解决方法吗?
PS:这是在 bash 中完成的。
答案1
在类似 Korn 的 shell 中,time
是引入以下内容的关键字:
time <pipeline>
构造。什么time
时候是管道了,就是用管道连接在一起的命令。
time for i in 1 2; do
echo "$i"
done 2>&1 | {
read a
read b
ls /etc /x
} 2> /dev/null
time ls 2>&1
是按 计时的管道示例time
。
time
管道中的进程返回后,统计信息将报告在 shell 的 stderr 上,但在管道的每个计时部分中,2> ...
它们不会重定向time
的统计输出。
您需要 stderr 已被重定向前对该time ...
构造进行评估。例如:
{ time <pipeline>; } 2> ...
eval 'time <pipeline>' 2> ...
exec 2> ...; time <pipeline>
要仅重定向time
输出而不重定向 中命令的错误<pipeline>
,您可以将先前的 stderr 保存在另一个上fd
,并在正在计时的管道中恢复它。例如:
{
time {
<pipeline>
} 2>&3 3>&-
} 3>&2 2> ...
将该输出传送到另一个命令:
{
{
time {
<pipeline>
} 2>&3 3>&-
} 3>&2 2>&1 >&4 4>&- | another command 4>&-
} 4>&-
在 fd 4 上保存后,我们还需要恢复标准输出。
要将所有 stdout、stderr 和time
统计信息传递给命令,只需执行以下操作:
{ time <pipeline>; } 2>&1 | a command
答案2
我认为您希望将每个原型的输出time
和输出包含在同一个日志文件中:
#!/bin/bash
# Name as "algon1" (
echo "Timing algorithm1:"
time algo1 >/dev/null
echo "Timing algorithm2:"
time algo2 >/dev/null
echo "Timing algorithm3:"
time algo3 >/dev/null
) > algon1.log 2>&1
然后使文件可执行并调用它
chmod a+x algon1
./algon1
或者,如果您不希望将输出文件名硬编码到脚本中,而是将输出写入标准输出:
#!/bin/bash
# Name as "algon2"
(
echo "Timing algorithm1:"
time algo1 >/dev/null
echo "Timing algorithm2:"
time algo2 >/dev/null
echo "Timing algorithm3:"
time algo3 >/dev/null
) 2>&1
和
chmod a+x algon2
./algon2 | tee algon2.log
在这两个脚本中,如果您希望算法的输出散布有计时,则可以>/dev/null
从每一行中删除 。time
答案3
在脚本的开头定义重定向:
#!/bin/bash
exec 2>&1
echo Timing ls 1
time ls &>/dev/null
echo Timing ls 2
time ls /jabberwocks &>/dev/null
./time_ls.sh > ls_sh.meas