如何在脚本本身内重定向整个shell脚本的输出?

时间:2008-11-24 16:28:21

标签: shell

是否可以将Bourne shell脚本的所有输出重定向到某个地方,但脚本本身内部有shell命令?

重定向单个命令的输出很简单,但我想要更像这样的东西:

#!/bin/sh
if [ ! -t 0 ]; then
    # redirect all of my output to a file here
fi

# rest of script...

含义:如果脚本以非交互方式运行(例如,cron),则将所有内容的输出保存到文件中。如果从shell以交互方式运行,请让输出像往常一样转到stdout。

我想为通常由FreeBSD定期实用程序运行的脚本执行此操作。它是日常运行的一部分,我通常不会每天都看到电子邮件,所以我没有发送它。但是,如果这个特定脚本中的某些内容失败,那对我来说很重要,我希望能够捕获并通过电子邮件发送这部分日常工作的输出。

更新:Joshua的回答是正确的,但我也希望在整个脚本周围保存和恢复stdout和stderr,这样做:

# save stdout and stderr to file descriptors 3 and 4, then redirect them to "foo"
exec 3>&1 4>&2 >foo 2>&1

# ...

# restore stdout and stderr
exec 1>&3 2>&4

5 个答案:

答案 0 :(得分:145)

通常我们会将其中一个放在脚本顶部或附近。解析命令行的脚本将在解析后进行重定向。

将标准输出发送到文件

exec > file

使用stderr

exec > file                                                                      
exec 2>&1

将stdout和stderr附加到文件

exec >> file
exec 2>&1

作为Jonathan Leffler mentioned in his comment

exec有两个独立的工作。第一个是用新程序替换当前正在执行的shell(脚本)。另一种是改变当前shell中的I / O重定向。这是因为exec没有参数。

答案 1 :(得分:125)

将问题解决为已更新。

#...part of script without redirection...

{
    #...part of script with redirection...
} > file1 2>file2 # ...and others as appropriate...

#...residue of script without redirection...

大括号“{...}”提供了一个I / O重定向单元。大括号必须出现在命令可能出现的位置 - 简单地说,在行的开头或分号后。 (是的,可以更精确;如果你想狡辩,请告诉我。

你是正确的,你可以保留原始的stdout和stderr与你显示的重定向,但对于那些必须稍后维护脚本的人来说,如果你对重定向代码的范围如上所示,通常会更简单

答案 2 :(得分:28)

您可以将整个脚本设为如下函数:

main_function() {
  do_things_here
}

然后在脚本的末尾有这个:

if [ -z $TERM ]; then
  # if not run via terminal, log everything into a log file
  main_function 2>&1 >> /var/log/my_uber_script.log
else
  # run via terminal, only output to screen
  main_function
fi

或者,您可以在每次运行时将所有内容记录到日志文件中,然后只需执行以下操作即可将其输出到stdout:

# log everything, but also output to stdout
main_function 2>&1 | tee -a /var/log/my_uber_script.log

答案 3 :(得分:6)

要保存原始标准输出和stderr,您可以使用:

exec [fd number]<&1 
exec [fd number]<&2

例如,以下代码将打印&#34; walla1&#34;和&#34; walla2&#34;到日志文件(a.txt),&#34; walla3&#34; stdout,&#34; walla4&#34;到stderr。

#!/bin/bash

exec 5<&1
exec 6<&2

exec 1> ~/a.txt 2>&1

echo "walla1"
echo "walla2" >&2
echo "walla3" >&5
echo "walla4" >&6

答案 4 :(得分:3)

[ -t <&0 ] || exec >> test.log