写STDOUT& STDERR为日志文件,也将STDERR写入屏幕

时间:2010-05-20 05:30:59

标签: bash unix shell

我想运行几个命令,并将所有输出捕获到日志文件中。我还想将任何错误打印到屏幕上(或者可选地将输出邮寄给某人)。

这是一个例子。以下命令将运行三个命令,并将所有输出(STDOUT和STDERR)写入单个日志文件。

{ command1 && command2 && command3 ; } > logfile.log 2>&1

以下是我想对这些命令的输出做的事情:

  • 所有命令的STDERR和STDOUT都会转到日志文件中,以防我以后需要它 - 除非有问题,否则我通常不会在这里查看。
  • 将STDERR打印到屏幕(或者可选地,管道到/ bin / mail),这样任何错误都会突出而不会被忽略。
  • 如果返回代码仍然可用,那将是很好的,这样我就可以进行一些错误处理。如果出现错误,我想发送电子邮件,例如:

    {command1&& command2&& command3; }> logfile.log 2>& 1 || mailx -s“出现错误”stefanl@example.org

我遇到的问题是STDERR在I / O重定向期间丢失了上下文。 '2>& 1'将STDERR转换为STDOUT,因此如果我做2>我无法查看错误。 error.log中

以下是几个多汁的例子。让我假装我正在运行一些熟悉的构建命令,但我不希望整个构建因为一个错误而停止,所以我使用'--keep-going'标志。

{ ./configure && make --keep-going && make install ; } > build.log 2>&1

或者,这是一个简单的(也许是草率的)构建和部署脚本,它会在发生错误时继续运行。

{ ./configure && make --keep-going && make install && rsync -av --keep-going /foo devhost:/foo} > build-and-deploy.log 2>&1

我认为我想要的是某种Bash I/O Redirection,但我无法弄明白。

5 个答案:

答案 0 :(得分:16)

(./doit >> log) 2>&1 | tee -a log

这将使用stdout并将其附加到日志文件。

然后stderr将转换为stdout,将其传送到tee,并将其附加到日志中(如果您有Bash 4,则可以将2>&1 |替换为|&)并且将它发送到stdout,它将出现在tty上,或者可以通过管道输送给另一个命令。

我对两者都使用了append模式,这样无论shell重定向和tee打开文件的顺序如何,你都不会吹掉原文。也就是说,stderr / stdout可能以意想不到的方式交错。

答案 1 :(得分:1)

如果你的系统有/ dev / fd / *节点,你可以这样做:

( exec 5>logfile.txt ; { command1 && command2 && command3 ;} 2>&1 >&5 | tee /dev/fd/5 )

这会打开日志文件的文件描述符5。执行命令,标准错误指向标准输出,标准输出指向fd 5,管道标准输出(现在只包含stderr)到tee,它将输出复制到fd 5,这是日志文件。

答案 2 :(得分:1)

以下是如何运行一个或多个命令,捕获标准输出和错误,按生成顺序,到日志文件,并在任何终端屏幕上仅显示标准错误你喜欢。适用于linux上的bash。可能适用于大多数其他环境。我将用一个例子来说明它是如何完成的。

预赛:

打开两个窗口(shell,tmux会话,等等)

我将演示一些测试文件,因此创建测试文件:

touch /tmp/foo /tmp/foo1 /tmp/foo2
在window1中

mkfifo /tmp/fifo

0</tmp/fifo cat - >/tmp/logfile

然后,在window2中:

(ls -l /tmp/foo /tmp/nofile /tmp/foo1 /tmp/nofile /tmp/nofile; echo successful test; ls /tmp/nofile1111) 2>&1 1>/tmp/fifo | tee /tmp/fifo 1>/dev/pts/2

/dev/pts/2替换为您希望stderr显示的任何tty。

子shell中各种成功和失败命令的原因只是生成混合的输出和错误消息流,以便您可以在日志文件中验证正确的顺序。一旦理解了它的工作原理,用你选择的脚本或命令替换“ls”和“echo”命令。

使用此方法,将保留输出和错误的顺序,语法简单而干净,并且只有一个对输出文件的引用。此外,还可以灵活地将stderr的额外副本放在任何地方。

答案 3 :(得分:0)

尝试:

command 2>&1 | tee output.txt

此外,您可以将stdout和stderr指向不同的地方:

command > stdout.txt >& stderr.txt

command > stdout.txt |& program_for_stderr

所以上面的一些组合应该适合你 - 例如你可以将stdout保存到一个文件中,并将stderr保存到一个文件和管道到另一个程序(使用tee)。

答案 4 :(得分:0)

在脚本开头添加

#!/bin/bash
set -e 
outfile=logfile

exec > >(cat >> $outfile)
exec 2> >(tee -a $outfile >&2)

# write your code here

STDOUTSTDERR将写入$outfile,只有STDERR才能在控制台上看到