将 stderr 重定向到 stdout 到脚本中的文件

将 stderr 重定向到 stdout 到脚本中的文件

我有几种不同的算法,我需要对其进行原型设计。

所以我制作了原型程序和脚本。调用的脚本time.sh看起来像这样

echo "Timing algorithm1:"
time algo1 >dev/null

echo "Timing algorithm2:"
time algo2 >dev/null

echo "Timing algorithm3:"
time algo3 >dev/null

...

现在为了简单起见,替换lsalgo1...(我不想为每个算法发布代码,强迫人们编译它...)

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

相关内容