在有限的环境中,将stdout和stderr输出到文件,将屏幕和stderr输出到文件

编程入门 行业动态 更新时间:2024-10-15 18:25:56
本文介绍了在有限的环境中,将stdout和stderr输出到文件,将屏幕和stderr输出到文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

使用mkfifo可能可以解决此问题,但在我的QNAP中不存在此问题。因此,以下是对问题的描述以及我到目前为止所尝试的内容。

我有一个名为activateLogs的函数,如果将日志写入磁盘或两者(屏幕和磁盘),该函数都会重新启动脚本。这两个选项都是我要实现的新功能。

exec 3<> "$logPath/$logFileName.log" "$0" "${mainArgs[@]}" 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" 1>&3 &

这段代码是写入磁盘的版本。mainArgs包含传递给脚本的所有参数,并在此函数中定义。此解决方案来自stackoverflow/a/45426547/214898。它将stderr&;stdout合并到一个文件中,并仍然在另一个文件中输出stderr。

因此,现在,我希望能够保留它,并将打印标准输出添加到屏幕(&A)。

无法应用上面链接的问题中接受的解决方案,因为脚本正在使用sh运行,而mkfifo不存在。

尝试#1

exec 3>&1 "$0" "${mainArgs[@]}" 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" 1>&3 &

--&>为了替换上述代码,我在if分支(已存在)中添加了tee命令。

local isFileDescriptor3Exist=$(command 2>/dev/null >&3 && echo "Y") if [ "$isFileDescriptor3Exist" = "Y" ]; then tee -a "logs/123.log" & echo "Logs are configured" else ### CODE ABOVE fi

我有屏幕和错误文件,但日志文件为空。

尝试#2 现在,上述if分支中没有T形三通,但包含在重新启动命令中。

exec 3>&1 "$0" "${mainArgs[@]}" 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" 1>&3 3>&1 | tee -a "logs/123.log" &

结果相同。我在这个文件中可以理解,第一个tee最初不写入文件描述符#3,因此,3>&1什么也不做。

尝试#3(不再重新启动脚本)

out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$" busybox mkfifo "$out" "$err" trap 'rm "$out" "$err"' EXIT tee -a "$logPath/$logFileName.log" & tee -a "$logPath/$logFileName.err" < "$err" >&2 & command >"$out" 2>"$err"

我正在从busyboxmkfifo: applet not found获取mkfifo: applet not found

尝试#4(不再重新启动脚本)

out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$" python -c "import os; os.mkfifo("$out")" python -c "import os; os.mkfifo("$err")" trap 'rm "$out" "$err"' EXIT tee -a "$logPath/$logFileName.log" & tee -a "$logPath/$logFileName.err" < "$err" >&2 & command >"$out" 2>"$err" 我没有日志(既没有真实日志也没有错误)。不过,临时文件会被删除。此外,脚本永远不会结束,这是由trap引起的。

尝试#5

exec 3>&1 { "$0" "${mainArgs[@]}" | tee -a "$logPath/$logFileName.log"; } 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" & exit 该解决方案看起来很有希望,但现在重新启动脚本不起作用,因为我的代码会检测当前是否正在执行并停止它。这是正常的,因为它是在子进程中执行的,尽管我在整行末尾使用了&,但是.(边写边测试)。将终止符;替换为&已修复该问题。

尝试#6

我没有立即意识到这一点,但屏幕上显示了stdout&;stderr,stderr被写入文件,但只将stdout写入文件,而不是两者都写入。

exec 3>&1 { "$0" "${mainArgs[@]}" | tee -a "$logPath/$logFileName.log" & } 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" & exit

最终版本正在运行

现在,所有内容都写入/显示在它应该在的位置。请参阅接受答案中的完整代码。

{ "$0" "${mainArgs[@]}" 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" 1>&3 & } 3>&1 | tee -a "$logPath/$logFileName.log" & exit

令人难以置信的是,我的第一次尝试如此接近解决方案。

推荐答案

终于达到目标。我想说,@WilliamPursell的回答给了我灵感。

{ "$0" "${mainArgs[@]}" 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" 1>&3 & } 3>&1 | tee -a "$logPath/$logFileName.log" &

说明

  • 使用.
  • 重新启动脚本
  • 正在将标准错误(2>&1)发送到标准输出和.
  • 将标准输出发送到新的文件描述符(1>&3)
  • 通过管道将其传送到接收stderr的TEE以复制文件中的错误,并使用.
  • 将其传送到文件描述符#1
  • 正在将标准输出发送到新文件描述符(1>&3).
  • 并有&确保无阻塞
  • 然后使用大括号对前面的命令进行分组。
  • 将分组命令新文件描述符发送到标准输出(3>&1)
  • 通过管道将其传送到接收标准输出的TEE,该标准输出将错误和写入文件并显示在屏幕上的正常输出组合在一起
  • 并有&确保无阻塞

我的activateLogs函数的完整代码供感兴趣的人使用。我还包括了依赖项,即使它们可以插入到activateLogs函数中。

m=0 declare -a mainArgs if [ ! "$#" = "0" ]; then for arg in "$@"; do mainArgs[$m]=$arg m=$(($m + 1)) done fi function containsElement() # $1 string to find # $2 array to search in # return 0 if there is a match, otherwise 1 { local e match="$1" shift for e; do [[ "$e" == "$match" ]] && return 0; done return 1 } function hasMainArg() # $1 string to find # return 0 if there is a match, otherwise 1 { local match="$1" containsElement "$1" "${mainArgs[@]}" return $? } function activateLogs() # $1 = logOutput: What is the output for logs: SCREEN, DISK, BOTH. Default is DISK. Optional parameter. { local logOutput=$1 if [ "$logOutput" != "SCREEN" ] && [ "$logOutput" != "BOTH" ]; then logOutput="DISK" fi if [ "$logOutput" = "SCREEN" ]; then echo "Logs will only be output to screen" return fi hasMainArg "--force-log" local forceLog=$? local isFileDescriptor3Exist=$(command 2>/dev/null >&3 && echo "Y") if [ "$isFileDescriptor3Exist" = "Y" ]; then echo "Logs are configured" elif [ "$forceLog" = "1" ] && ([ ! -t 1 ] || [ ! -t 2 ]); then # Use external file descriptor if they are set except if having "--force-log" echo "Logs are configured externally" else echo "Relaunching with logs files" local logPath="logs" if [ ! -d $logPath ]; then mkdir $logPath; fi local logFileName=$(basename "$0")"."$(date +%Y-%m-%d.%k-%M-%S) exec 4<> "$logPath/$logFileName.log" # File descriptor created only to get the underlying file in any output option if [ "$logOutput" = "DISK" ]; then # FROM: stackoverflow/a/45426547/214898 exec 3<> "$logPath/$logFileName.log" "$0" "${mainArgs[@]}" 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" 1>&3 & else # FROM: stackoverflow/a/70790574/214898 { "$0" "${mainArgs[@]}" 2>&1 1>&3 | tee -a "$logPath/$logFileName.err" 1>&3 & } 3>&1 | tee -a "$logPath/$logFileName.log" & fi exit fi } #activateLogs "DISK" #activateLogs "SCREEN" activateLogs "BOTH" echo "FIRST" echo "ERROR" >&2 echo "LAST" echo "LAST2"

更多推荐

在有限的环境中,将stdout和stderr输出到文件,将屏幕和stderr输出到文件

本文发布于:2023-06-11 14:51:54,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/637067.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:文件   屏幕   环境   stderr   stdout

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!