为了账号安全,请及时绑定邮箱和手机立即绑定

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

/ 猿问

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

函数式编程 2019-08-23 16:01:31

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

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

exec > foo.log
echo test

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

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

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

script | tee foo.log

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

我试过了

exec | tee foo.log

但它不起作用。


查看完整描述

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>&1


echo "foo"

echo "bar" >&2

请注意,这bash不是sh。如果使用调用脚本sh myscript.sh,则会出现错误syntax error near unexpected token '>'。


如果您正在使用信号陷阱,则可能需要使用该tee -i选项以避免在发生信号时中断输出。(感谢JamesThomasMoon1979的评论。)


根据是否写入管道或终端(ls例如,使用颜色和列化输出)来更改输出的工具将检测上述构造,意味着它们输出到管道。


有一些选项可以强制执行着色/列化(例如ls -C --color=always)。请注意,这将导致颜色代码也被写入日志文件,从而降低了可读性。


查看完整回答
反对 回复 2019-08-23
?
慕莱坞森

busybox,macOS bash和非bash shell的解决方案


接受的答案肯定是bash的最佳选择。我在没有访问bash的Busybox环境中工作,并且它不理解exec > >(tee log.txt)语法。它也无法exec >$PIPE正常工作,尝试创建一个与命名管道同名的普通文件,该文件失败并挂起。


希望这对没有bash的其他人有用。


此外,对于使用命名管道的任何人来说,它是安全的rm $PIPE,因为它取消了管道与VFS的链接,但使用它的进程仍然保持引用计数,直到它们完成。


注意$ *的使用不一定安全。


#!/bin/sh


if [ "$SELF_LOGGING" != "1" ]

then

    # The parent process will enter this branch and set up logging


    # Create a named piped for logging the child's output

    PIPE=tmp.fifo

    mkfifo $PIPE


    # Launch the child process with stdout redirected to the named pipe

    SELF_LOGGING=1 sh $0 $* >$PIPE &


    # Save PID of child process

    PID=$!


    # Launch tee in a separate process

    tee logfile <$PIPE &


    # Unlink $PIPE because the parent process no longer needs it

    rm $PIPE    


    # Wait for child process, which is running the rest of this script

    wait $PID


    # Return the error code from the child process

    exit $?

fi


# The rest of the script goes here


查看完整回答
反对 回复 2019-08-23
?
桃花长相依

不能说我对基于exec的任何解决方案感到满意。我更喜欢直接使用tee,因此我会在请求时使用tee调用脚本:


# my script: 


check_tee_output()

{

    # copy (append) stdout and stderr to log file if TEE is unset or true

    if [[ -z $TEE || "$TEE" == true ]]; then 

        echo '-------------------------------------------' >> log.txt

        echo '***' $(date) $0 $@ >> log.txt

        TEE=false $0 $@ 2>&1 | tee --append log.txt

        exit $?

    fi 

}


check_tee_output $@


rest of my script

这允许您这样做:


your_script.sh args           # tee 

TEE=true your_script.sh args  # tee 

TEE=false your_script.sh args # don't tee

export TEE=false

your_script.sh args           # tee

您可以自定义此选项,例如,将tee = false替换为默认值,使TEE保持日志文件等等。我猜这个解决方案类似于jbarlow的,但更简单,也许我有一些限制,我还没有遇到过。


查看完整回答
反对 回复 2019-08-23

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信