将 *unbuffered* 标准输出从 bash 脚本本身复制到文件
Posted
技术标签:
【中文标题】将 *unbuffered* 标准输出从 bash 脚本本身复制到文件【英文标题】:Copy *unbuffered* stdout to file from within bash script itself 【发布时间】:2015-06-22 08:34:26 【问题描述】:我想将标准输出从 within 复制到一个 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"
这可行,但在脚本完成之前输出被缓冲的缺点,正如链接答案中所讨论的那样。在上面的例子中,“hello”和“world”都会在 10 秒后才显示在日志中。
我知道 stdbuf 命令,如果使用
运行脚本stdbuf -oL ./myscript.sh
然后 stdout 确实连续打印到文件和终端。 但是,我也希望在脚本中处理这个问题。有没有办法将这两种解决方案结合起来?我宁愿不求助于包装脚本,它只是调用包含“stdbuf -oL”的原始脚本。
【问题讨论】:
【参考方案1】:如果存在特殊参数,您可以使用解决方法并使用 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
,这不是您的脚本。解决这个问题不在这个问题的范围内。
【讨论】:
谢谢。这些限制确实没问题。 Tbh 这可能不是最干净的解决方案 :-) 但我会试试的。【参考方案2】:第一个解决方案的延迟是由sed
引起的,而不是由tee
引起的。试试这个:
#!/bin/bash
exec 6>&1 2>&1>&>(tee -a myscript.log)
要“撤消”tee
效果:
exec 1>&6 2>&6 6>&-
【讨论】:
谢谢。你确定 tee vs sed 吗?很确定在没有 sed 的情况下也会发生同样的事情,但我会仔细检查。另外,您介意解释一下您的建议是做什么的吗? 6 是什么? 我遇到了similar 问题(乍一看并没有完全连接到您的问题),其中我试图通过将某个进程的标准输出传送到 sed/perl 来dos2unix
某个进程的输出/tr/dos2unix/etc 并同时使用tee
复制它。当两者都启用时,我无法摆脱烦人的延迟/缓冲效果。我最终决定tee
only 并在以后执行dos2unix
。有关将 stdout/stderr 重定向到 fd6 here 的更多信息
sed
上的 -u, --unbuffered
选项应该,正如 help
所说,load minimal amounts of data from the input files and flush the output buffers more often
。以上是关于将 *unbuffered* 标准输出从 bash 脚本本身复制到文件的主要内容,如果未能解决你的问题,请参考以下文章
Linux python -u参数,设置无缓存输出(unbuffered)(无缓冲不缓冲不缓存)(实时重定向输出)
从 bash 脚本本身将 stdout 的副本重定向到日志文件