将* unbuffered * stdout从bash脚本本身复制到文件

时间:2015-06-22 08:34:27

标签: bash shell stdout named-pipes tee

我想将stdout复制到来自 bash脚本中的日志文件,这意味着我不想通过输出管道调用脚本来发送tee,我希望脚本本身能够处理它。我已成功使用this答案来完成此操作,使用以下代码:

#!/bin/bash
exec > >(sed "s/^/[${1}] /" | tee -a myscript.log)
exec 2>&1

# <rest of script>
echo "hello"
sleep 10
echo "world"

这样可行,但是在脚本完成之前,输出的缺点是缓冲,如链接的答案中所述。在上面的例子中,只有在10秒过后,“hello”和“world”才会显示在日志中。

我知道stdbuf命令,如果用

运行脚本
stdbuf -oL ./myscript.sh 

然后stdout确实连续打印到文件和终端。 但是,我希望这也可以在脚本中处理。有没有办法将这两种解决方案结合起来?我宁愿不使用一个包装脚本来简单地调用用“stdbuf -oL”括起来的原始脚本。

2 个答案:

答案 0 :(得分:0)

如果存在特殊参数,您可以使用变通方法并使脚本使用stdbuf执行自身:

#!/bin/bash

if [[ "$1" != __BUFFERED__ ]]; then
    prog="$0"
    stdbuf -oL "$prog" __BUFFERED__ "$@"
else
    shift #discard __BUFFERED__

    exec > >(sed "s/^/[${1}] /" | tee -a myscript.log)
    exec 2>&1

    # <rest of script>
    echo "hello"
    sleep 1
    echo "world"
fi

这将主要起作用:

  • 如果您使用./test运行脚本,则会显示无缓冲的[] hello\n[] world
  • 如果您使用./test 123 456运行脚本,则会显示您想要的[123] hello\n[123] world
  • 它不会起作用,但是,如果您使用bash test运行它 - $0设置为test,而不是您的脚本。但是,解决这个问题并不在这个问题的范围内。

答案 1 :(得分:0)

第一个解决方案的延迟是由sed引起的,而不是tee引起的。试试这个:

#!/bin/bash
exec 6>&1 2>&1>&>(tee -a myscript.log)

要“撤消”tee效果:

exec 1>&6 2>&6 6>&-