将文本附加到 bash 中的 stderr 重定向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/420278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 20:36:50  来源:igfitidea点击:

Append text to stderr redirects in bash

bashexecstderr

提问by dragonmantank

Right now I'm using exec to redirect stderr to an error log with

现在我正在使用 exec 将 stderr 重定向到错误日志

exec 2>> ${errorLog}

The only downside is that I have to start each run with a timestamp since exec just pushes the text straight into the log file. Is there a way to redirect stderr but allow me to append text to it, such as a time stamp?

唯一的缺点是我必须用时间戳开始每次运行,因为 exec 只是将文本直接推送到日志文件中。有没有办法重定向 stderr 但允许我向其附加文本,例如时间戳?

回答by Johannes Schaub - litb

This is very interesting. I've asked a guy who knows bash quite well, and he told me this way:

这是非常有趣的。我问过一个非常了解 bash 的人,他是这样告诉我的:

 foo() { while IFS='' read -r line; do echo "$(date) $line" >> file.txt; done; };

First, that creates a function reading one line of raw input from stdin, while the assignment to IFS makes it doesn't ignore blanks. Having read one line, it outputs it with the appropriate data prepended. Then you have to tell bash to redirect stderr into that function:

首先,它创建了一个从标准输入读取一行原始输入的函数,而对 IFS 的赋值使它不会忽略空白。读取一行后,它会输出它并预先添加适当的数据。然后你必须告诉 bash 将 stderr 重定向到该函数:

exec 2> >(foo)

Everything you write into stderr will now go through the foo function. Note when you do it in an interactive shell, you won't see the prompt anymore, because it's printed to stderr, and the read in foo is line buffered :)

您写入 stderr 的所有内容现在都将通过 foo 函数。请注意,当您在交互式 shell 中执行此操作时,您将不会再看到提示,因为它已打印到 stderr,并且 foo 中的读取是行缓冲的 :)

回答by Matya

You could simple just use:

你可以简单地使用:

exec 1> >( sed "s/^/$(date '+[%F %T]'): /" | tee -a ${LOGFILE}) 2>&1

This will not completely solve your Problem regarding Prompt not shown (itt will show after a short time, but not realtime, since the pipe will cache some data...), but will display the output 1:1 on stdout as well as in the file.

这不会完全解决您关于未显示提示的问题(它会在很短的时间后显示,但不是实时显示,因为管道会缓存一些数据......),但会在 stdout 和 in文件。

The only problem is, that I could not solve, is, to do this from a function, since that opens a subshell, where the exec is useless for the main program...

唯一的问题是,我无法解决的是,从函数中执行此操作,因为这会打开一个子shell,其中 exec 对主程序无用...

回答by ceving

This example redirects stdout and stderr without loosing the original stdout and stderr. Also errors in the stdout handler are logged to the stderr handler. The file descriptors are saved in variables and closed in the child processes. Bash takes care, that no collisions occur.

此示例在不丢失原始 stdout 和 stderr 的情况下重定向 stdout 和 stderr。stdout 处理程序中的错误也会记录到 stderr 处理程序中。文件描述符保存在变量中并在子进程中关闭。Bash 小心,不会发生冲突。

#! /bin/bash

stamp ()
{
  local LINE
  while IFS='' read -r LINE; do
    echo "$(date '+%Y-%m-%d %H:%M:%S,%N %z') $$ $LINE"
  done
}

exec {STDOUT}>&1
exec {STDERR}>&2
exec 2> >(exec {STDOUT}>&-; exec {STDERR}>&-; exec &>> stderr.log; stamp)
exec > >(exec {STDOUT}>&-; exec {STDERR}>&-; exec >> stdout.log; stamp)

for n in $(seq 3); do
  echo loop $n >&$STDOUT
  echo o$n
  echo e$n >&2
done

This requires a current Bash version but thanks to Shellshockone can rely on this nowadays.

这需要当前的 Bash 版本,但多亏了Shellshock,现在人们可以依靠它了。

回答by user3428156

cat q23123  2> tmp_file ;cat tmp_file | sed -e "s/^/$(date '+[%F %T]'): /g" >> output.log; rm -f tmp_file