猿问
下载APP

将stdout的COPY重定向到bash脚本本身的日志文件

将stdout的COPY重定向到bash脚本本身的日志文件

我知道如何将stdout重定向到文件:

exec > foo.log
echo test

这会将'test'放入foo.log文件中。

现在我想将输出重定向到日志文件并将其保存在stdout上

即它可以从脚本外部轻松完成:

script | tee foo.log

但我想在脚本本身内声明它

我试过了

exec | tee foo.log

但它不起作用。


函数式编程
浏览 48回答 3
3回答

智慧大石

#!/usr/bin/env bash# Redirect stdout ( > ) into a named pipe ( >() ) running "tee"exec > >(tee -i logfile.txt)# Without this, only stdout would be captured - i.e. your# log file would not contain any error messages.# SEE (and upvote) the answer by Adam Spiers, which keeps STDERR# as a separate stream - I did not want to steal from him by simply# adding his answer to mine.exec 2>&1echo "foo"echo "bar" >&2请注意,这bash不是sh。如果使用调用脚本sh myscript.sh,则会出现错误syntax error near unexpected token '>'。如果您正在使用信号陷阱,则可能需要使用该tee -i选项以避免在发生信号时中断输出。(感谢JamesThomasMoon1979的评论。)根据是否写入管道或终端(ls例如,使用颜色和列化输出)来更改输出的工具将检测上述构造,意味着它们输出到管道。有一些选项可以强制执行着色/列化(例如ls -C --color=always)。请注意,这将导致颜色代码也被写入日志文件,从而降低了可读性。

慕莱坞森

busybox,macOS bash和非bash shell的解决方案接受的答案肯定是bash的最佳选择。我在没有访问bash的Busybox环境中工作,并且它不理解exec > >(tee log.txt)语法。它也无法exec >$PIPE正常工作,尝试创建一个与命名管道同名的普通文件,该文件失败并挂起。希望这对没有bash的其他人有用。此外,对于使用命名管道的任何人来说,它是安全的rm $PIPE,因为它取消了管道与VFS的链接,但使用它的进程仍然保持引用计数,直到它们完成。注意$ *的使用不一定安全。#!/bin/shif [ "$SELF_LOGGING" != "1" ]then&nbsp; &nbsp; # The parent process will enter this branch and set up logging&nbsp; &nbsp; # Create a named piped for logging the child's output&nbsp; &nbsp; PIPE=tmp.fifo&nbsp; &nbsp; mkfifo $PIPE&nbsp; &nbsp; # Launch the child process with stdout redirected to the named pipe&nbsp; &nbsp; SELF_LOGGING=1 sh $0 $* >$PIPE &&nbsp; &nbsp; # Save PID of child process&nbsp; &nbsp; PID=$!&nbsp; &nbsp; # Launch tee in a separate process&nbsp; &nbsp; tee logfile <$PIPE &&nbsp; &nbsp; # Unlink $PIPE because the parent process no longer needs it&nbsp; &nbsp; rm $PIPE&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; # Wait for child process, which is running the rest of this script&nbsp; &nbsp; wait $PID&nbsp; &nbsp; # Return the error code from the child process&nbsp; &nbsp; exit $?fi# The rest of the script goes here

桃花长相依

不能说我对基于exec的任何解决方案感到满意。我更喜欢直接使用tee,因此我会在请求时使用tee调用脚本:# my script:&nbsp;check_tee_output(){&nbsp; &nbsp; # copy (append) stdout and stderr to log file if TEE is unset or true&nbsp; &nbsp; if [[ -z $TEE || "$TEE" == true ]]; then&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; echo '-------------------------------------------' >> log.txt&nbsp; &nbsp; &nbsp; &nbsp; echo '***' $(date) $0 $@ >> log.txt&nbsp; &nbsp; &nbsp; &nbsp; TEE=false $0 $@ 2>&1 | tee --append log.txt&nbsp; &nbsp; &nbsp; &nbsp; exit $?&nbsp; &nbsp; fi&nbsp;}check_tee_output $@rest of my script这允许您这样做:your_script.sh args&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# tee&nbsp;TEE=true your_script.sh args&nbsp; # tee&nbsp;TEE=false your_script.sh args # don't teeexport TEE=falseyour_script.sh args&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# tee您可以自定义此选项,例如,将tee = false替换为默认值,使TEE保持日志文件等等。我猜这个解决方案类似于jbarlow的,但更简单,也许我有一些限制,我还没有遇到过。
打开App,查看更多内容
随时随地看视频慕课网APP
我要回答