是否可以将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
Joshua.. 161
通常我们会将其中一个放在脚本顶部或附近.解析其命令行的脚本将在解析后执行重定向.
将stdout发送到文件
exec > file
与stderr
exec > file exec 2>&1
将stdout和stderr追加到文件中
exec >> file exec 2>&1
正如Jonathan Leffler 在评论中提到的那样:
exec
有两个独立的工作.第一个是用新程序替换当前正在执行的shell(脚本).另一种是改变当前shell中的I/O重定向.这是因为没有争论exec
.
通常我们会将其中一个放在脚本顶部或附近.解析其命令行的脚本将在解析后执行重定向.
将stdout发送到文件
exec > file
与stderr
exec > file exec 2>&1
将stdout和stderr追加到文件中
exec >> file exec 2>&1
正如Jonathan Leffler 在评论中提到的那样:
exec
有两个独立的工作.第一个是用新程序替换当前正在执行的shell(脚本).另一种是改变当前shell中的I/O重定向.这是因为没有争论exec
.
将问题解决为更新.
#...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以及你所展示的重定向,但对于那些必须稍后维护脚本的人来说,如果你按照上面的说明调整重定向代码的范围,通常会更容易理解.
您可以使整个脚本成为这样的函数:
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
或者,您可以在每次运行时将所有内容记录到logfile中,并通过简单地执行以下操作将其输出到stdout:
# log everything, but also output to stdout main_function 2>&1 | tee -a /var/log/my_uber_script.log
要保存原始的stdout和stderr,可以使用:
exec [fd number]<&1 exec [fd number]<&2
例如,以下代码将“ walla1”和“ walla2”打印到日志文件(a.txt
),将“ walla3”打印到标准输出,将“ walla4”打印到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