简体   繁体   English

分别重定向和重组stderr / stdout,而不会丢失顺序

[英]Separately redirecting and recombining stderr/stdout without losing ordering

I want to execute a command and want to redirect stderr and stdout as below: 我想执行一个命令,并想重定向stderr和stdout,如下所示:

stderr and stdout -> should be written ONLY to logs.log file while keeping the order stderr和stdout->仅应在保持顺序的同时写入logs.log文件

stderr -> should be printed to SCREEN and also written to errors.log stderr->应该打印到SCREEN并也写入errors.log

So far I can redirect them both to screen and the file log.txt like this: 到目前为止,我可以将它们重定向到屏幕和文件log.txt,如下所示:

command 2>&1 | tee logs.log

But the above is not what I need. 但是以上不是我所需要的。

To make it more clear again what the results needs to be. 为了更清楚地说明结果是什么。

After command is executed I need to see on screen only the result of stderr, I need to have one file named errors.log with stderr, and I need to have another file named logs.log with the result of both stdout and stderr in the original order in which they were created. 执行命令后,我只需要在屏幕上看到stderr的结果,我需要使用stderr创建一个名为errors.log的文件,而在目录中需要使用stdout和stderr生成另一个名为logs.log的文件。创建它们的原始顺序。

Preserving perfect order while performing separate redirections is not even theoretically possible without some ugly hackery. 从理论上讲,如果没有一些丑陋的黑客手段,则在执行单独的重定向时保持完美的顺序是不可能的。 Ordering is only preserved in writes (in O_APPEND mode) directly to the same file; 仅在直接写入同一文件(在O_APPEND模式下)时保留顺序。 as soon as you put something like tee in one process but not the other, ordering guarantees go out the window and can't be retrieved without keeping information about which syscalls were invoked in what order. 一旦在一个进程中放置了类似tee东西,而没有在另一个过程中放了东西,那么排序保证就会消失,并且如果不保留有关以什么顺序调用了哪些syscall的信息,就无法检索到。

So, what would that hackery look like? 那么,这种黑客将是什么样子? It might look something like this: 它可能看起来像这样:

# eat our initialization time *before* we start the background process
sudo sysdig-probe-loader

# now, start monitoring syscalls made by children of this shell that write to fd 1 or 2
# ...funnel content into our logs.log file
sudo sysdig -s 32768 -b -p '%evt.buffer' \
  "proc.apid=$$ and evt.type=write and (fd.num=1 or fd.num=2)" \
  > >(base64 -i -d >logs.log) \
  & sysdig_pid=$!

# Run your-program, with stderr going both to console and to errors.log
./your-program >/dev/null 2> >(tee errors.log)

That said, this remains ugly hackery: It only catches writes direct to FDs 1 and 2, and doesn't track any further redirections that may take place. 也就是说,这仍然是丑陋的骇客:它只捕获直接写入FD 1和FD 2的消息,并且不会跟踪可能发生的任何进一步重定向。 (This could be improved by performing the writes to FIFOs, and using sysdig to track writes to those FIFOs; that way fdup() and similar operations would work as-expected; but the above suffices to prove the concept). (这可以通过执行对FIFO的写操作,并使用sysdig跟踪对这些FIFO的写操作来改善;这样fdup()和类似的操作将按预期方式工作;但是以上足以证明这一概念)。


Making Separate Handling Explicit 明确进行单独处理

Here we demonstrate how to use this to colorize only stderr, and leave stdout alone -- by telling sysdig to generate a stream of JSON as output, and then iterating over that: 在这里,我们通过告诉sysdig生成JSON流作为输出,然后对其进行迭代,演示了如何使用此方法仅对stderr着色,并保持stdout sysdig

exec {colorizer_fd}> >(
  jq --unbuffered --arg startColor "$(tput setaf 1)" --arg endColor "$(tput sgr0)" -r '
    if .["fd.filename"] == "stdout" then
      ("STDOUT: " + .["evt.buffer"])
    else
      ("STDERR: " + $startColor + .["evt.buffer"] + $endColor)
    end
  '
)

sudo sysdig -s 32768 -j -p '%fd.filename %evt.buffer' \
  "proc.apid=$$ and evt.type=write and proc.name != jq and (fd.num=1 or fd.num=2)" \
  >&$colorizer_fd \
  & sysdig_pid=$!

# Run your-program, with stdout and stderr going to two separately-named destinations
./your-program >stdout 2>stderr

Because we're keying off the output filenames ( stdout and stderr ), these need to be constant for the above code to work -- any temporary directory desired can be used. 因为我们要取消输出文件名( stdoutstderr ),所以对于上面的代码来说,这些文件名必须是恒定的-可以使用所需的任何临时目录。


Obviously, you shouldn't actually do any of this. 显然,您实际上不应执行任何此类操作。 Update your program to support whatever logging infrastructure is available in its native language (Log4j in Java, the Python logging module, etc) to allow its logging to be configured explicitly. 更新程序以支持其本国语言(Java中的Log4j,Python日志记录模块等)可用的任何日志记录基础结构,以允许对其日志记录进行显式配置。

This will get you most of the way there: 这将为您提供大部分帮助:

your_command 2> >(tee -a logs.log errors.log) 1>>logs.log

but I don't think you'll be able to exactly preserve the order of the output in the logs.log file. 但我认为您将无法完全将输出的顺序保留在logs.log文件中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从后台进程重定向stdout和stderr - Redirecting stdout & stderr from background process 将stderr和stdout重定向到同一文件的顺序 - Order of redirecting stderr and stdout to the same file 将stdout和stderr重定向到C ++中的文件 - Redirecting stdout and stderr to a file in c++ 您可以傻傻地呆着并分别记录stdout和stderr吗? - Can you fool isatty AND log stdout and stderr separately? 处理stdout和stderr分别添加时间戳:错误的顺序 - Processing stdout and stderr separately adding a timestamp: Wrong order 为什么将 stderr 重定向到文件有效,但将 stderr 重定向到 stdout 不起作用? (Linux外壳) - Why does redirecting stderr to file work, but redirecting to stderr to stdout does not work? (linux shell) 将stderr,stdout和stdin重定向到管道会阻止进程运行 - Redirecting stderr, stdout and stdin to pipe is blocking the process from running 从脚本中将所有命令stdout / stderr重定向到日志文件 - Redirecting all commands stdout/stderr to a log file from within a script 将stdout和stderr重定向到其他程序,而无需更改退出代码 - Redirect stdout and stderr to different program without changing exit code 如何在没有`disown`或gdb的情况下关闭进程的stdout和stderr? - How to close a process's stdout and stderr without `disown` or gdb?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM