我正在寻找一种运行程序的方法Prog
并最终得到 3 个文件:
- 标准输出
Prog
- 标准错误
Prog
- 如果没有发生重定向, stdout 和 stderr 的
Prog
组合将会像在屏幕上一样。
是否有重定向、管道等的组合可以实现这一点?
注意:我通常使用 bash。
答案1
据我所知,没有优雅的方法可以做到这一点(对于一种不太优雅的方法,虽然可行但并不美观,请向下滚动到我的答案的末尾)。我怀疑你能做得更好:
$ command >stdout.txt 2>stderr.txt && cat stdout.txt stderr.txt > both.txt
有各种各样的 凉爽的 技巧您可以使用,但它们似乎都无法比上述方法更好地生成 3 个文件。主要问题是文件both.txt
不会按正确的顺序显示消息(STDERR 和 STDOUT)。这是因为(如解释的那样这里):
当您将标准输出和标准错误重定向到同一个文件时,您可能会得到一些意外结果。这是因为 STDOUT 是缓冲流,而 STDERR 始终是非缓冲的。这意味着 STDERR 的每个字符都会在可用时立即写入,而 STDOUT 会批量写入内容。当 STDOUT 和 STDERR 都转到同一个文件时,您可能会看到错误消息出现得比您预期的要早,与程序或脚本的实际输出有关。这并不是什么值得担心的事情,只是缓冲流与非缓冲流的副作用,您只需要记住这一点。
我能找到的最佳替代方案是使用 bash 子 shell,但有点复杂,仍然不会按正确顺序显示输出。我编写了一个简单的 Perl 脚本,test.pl
将“OUT”打印到STDOUT
并将“ERR”打印到STDERR
,重复该过程 3 次:
#/usr/bin/perl
for($i=0; $i<=2; $i++){
print STDOUT "OUT\n";
print STDERR "ERR\n"
}
其正常的、未重定向的输出是:
$ ./test.pl
OUT
ERR
OUT
ERR
OUT
ERR
为了重定向输出,我运行了:
(./test.pl 2> >(tee error.txt) > >(tee out.txt)) > both.txt
这使用tee
一个将其输入打印到屏幕上的程序和到文件名。因此,我将重定向STDERR
并将其作为输入传递给tee
,告诉它将其写入文件。与和文件error.txt
类似。我将整个内容放在子 shell ( ) 中,这样我就可以捕获STDOUT
out.txt
(...)
全部其输出并重定向到both.txt
。
现在,它可以正常工作,因为它创建了 3 个文件,一个包含STDERR
,一个包含STDOUT
,一个包含 和 。但是,如上所述,这会导致消息以错误的顺序出现在 中both.txt
:
$ cat both.txt
ERR
ERR
ERR
OUT
OUT
OUT
我能找到的唯一解决方法是将打印时间附加到每一行输出,然后进行排序,但是它变得越来越严重地很复杂,如果我处于你的位置,我会问自己这是否真的值得:
$(./test.pl \
2> >(while read n; do echo `date +%N`" $n"; echo "$n" >>error.txt; done) \
> >(while read n; do echo `date +%N`" $n"; echo "$n" >> out.txt; done )) \
| gawk '{print $2}'> both.txt
答案2
1)创建两个脚本:
getout.sh
geterr.sh
getout.sh 将接收 Stdout。
脚本将数据写入 f1.txt,并将相同数据写入文件 f12.txt
geterr.sh 将接收 Stderr。
脚本将数据写入 f2.txt,并将相同数据写入文件 f12.txt
我认为不可能可靠地保留写入文件 f12.txt 的数据的准确顺序。这是因为写入 Stdout 的操作由操作系统缓冲,而写入 Stderr 的操作几乎是实时发生的。这可能会(将)延迟脚本看到 Stdout 数据。这样做的效果是:
a. For some data written to Stdout BEFORE data written to
Stderr, the data written to f12.txt from Stderr may
precede the data written by Stdout.
b. Some data written to Stdout will be accumulated with
other data written earlier or later. As the script sees it,
these data lines may all appear at the same time (together).
c. Because of (b), for some data written to Stderr in-between
multiple data writes to Stdout, the data written to f12.txt
from Stderr may precede the whole group of data written to Stdout.
d. Because of all this, including timestamps with the data
written to f12.txt will not preserve the order that events happened.
2)创建2个命名管道:
% mknod pout p
% mknod perr p
3)让脚本“监听”管道:
% ./getout.sh < pout &
% ./geterr.sh < perr &
4)像这样启动你的程序(Prog):
% Prog 1> pout 2> perr
答案3
要将它们分成不同的文件:
./Prog 1> stdout.log 2> stderr.log
要将它们合并到同一个文件中:
./Prog 1>> combine.log 2>> combine.log
有一种“简写”方法可以对 bash 进行组合,但是如果您使用 sh,上述方法会更安全。
取决于你的联合收割机需要的精度,以下内容可能有效也可能无效
touch stdout.log
touch stderr.log
tail -f stdout.log >> combine.log &
tail -f stderr.log >> combine.log &
./Prog 1>> stdout.log 2>> stderr.log ; pkill tail