如何在脚本本身中redirect整个shell脚本的输出?

是否有可能将Bourne shell脚本的所有输出redirect到某处,但在脚本本身内部使用shell命令?

redirect单个命令的输出很容易,但是我想要更类似这样的东西:

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

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

我想对通常由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 

发送标准输出到一个文件

 exec > file 

与stderr

 exec > file exec 2>&1 

将stdout和stderr附加到文件

 exec >> file exec 2>&1 

解决问题更新。

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

大括号“{…}”提供I / Oredirect的单位。 大括号必须出现在命令可能出现的地方 – 简单地说,在一行的开头或分号后面。 ( 是的,这可以做得更精确;如果你想狡辩,让我知道。

你是对的,你可以保留原来的stdout和stderr与你显示的redirect,但是如果你按照上面所示的范围redirect的代码,稍后必须维护脚本来理解正在发生的事情的人通常更简单。

你可以使整个脚本像这样的function:

 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 

或者,您可以将所有内容都logging到日志文件中,然后通过简单的操作将其输出到stdout:

 # log everything, but also output to stdout main_function 2>&1 | tee -a /var/log/my_uber_script.log 
 [ -t <&0 ] || exec >> test.log 

为了保存原始的stdout和stderr,你可以使用:

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

例如,以下代码将打印“walla1”和“walla2”到日志文件( a.txt ),“walla3”到stdout,“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