Lor*_*ist 1 unix io-redirection
我正在尝试编写一个简单的脚本,该脚本采用标准输出和标准错误,并将该单词放在STDERR:标准错误每行的开头。为了进行测试,我有一个简单的脚本,它在标准输出和标准错误之间交替输出几行:
#!/usr/bin/perl
print "OUT 1\n";
print STDERR "ERR 1\n";
print "OUT 2\n";
print STDERR "ERR 2\n";
Run Code Online (Sandbox Code Playgroud)
当我运行它时:
lorkenpeist$ ./testscript.pl
OUT 1
ERR 1
OUT 2
ERR 2
Run Code Online (Sandbox Code Playgroud)
这是我stderr.awk要添加的脚本STDERR:
#!/bin/awk -f
{print "STDERR: " $0}
Run Code Online (Sandbox Code Playgroud)
如果我运行./testscript.pl | ./stderr.awk(这显然是错误的,因为我正在输出标准而不是标准错误):
lorkenpeist$ ./testscript.pl | ./stderr.awk
ERR 1
ERR 2
STDERR: OUT 1
STDERR: OUT 2
Run Code Online (Sandbox Code Playgroud)
我看到标准错误是立即输出的,而标准输出由于管道而被延迟。打印语句的原始顺序不会保留。
我还可以将标准错误重定向到标准输出:
lorkenpeist$ ./testscript.pl 2>&1 | ./stderr.awk
STDERR: ERR 1
STDERR: ERR 2
STDERR: OUT 1
STDERR: OUT 2
Run Code Online (Sandbox Code Playgroud)
不仅所有内容都被处理,而stderr.awk不仅仅是标准错误,而且打印语句的顺序也没有被保留。有没有办法只将标准错误发送到stderr.awk,并保留打印语句的顺序?我真正想看到的是:
OUT 1
STDERR: ERR 1
OUT 2
STDERR: ERR 2
Run Code Online (Sandbox Code Playgroud)
我开始怀疑 IO 重定向根本不是答案,但我找不到其他选择。
编辑: 鉴于标准输出是缓冲的而标准错误不是,看起来我无法完全控制打印语句在终端上出现的顺序。话虽如此,我希望至少在某种程度上保留顺序,而不是在任何标准输出之前打印所有标准错误。或者,有没有办法使标准输出和/或管道无缓冲?
像Andy Lutomirski一样,我认为如何管道 stderr 而不是 stdout可以提供帮助。
这是一个过滤标准错误而不更改标准输出的命令序列;./genouterr.sh生成有关标准输出和标准错误的信息。
( ./genouterr.sh 2>&1 1>&3 | sed 's/^/STDERR: /' >&2) 3>&1
Run Code Online (Sandbox Code Playgroud)
其作用是:
(...)并将其输出从文件描述符 3 发送到标准输出 ( 3>&1)。./genouterr.sh,将其标准输出通过管道传输到sed。2>&1),并将标准输出安排到文件描述符 3 ( 1>&3)。因此,脚本写入标准输出的任何内容实际上都会进入文件描述符 3,而脚本写入标准错误的任何内容都会进入管道。sed,在每行的开头插入STDERR:,然后将其标准输出重定向到标准错误 ( 1>&2)。最终结果是./genouterr.sh标准输出上写入的内容出现在标准输出上;标准错误上写入的内容./genouterr.sh以 为前缀STDERR:并出现在标准错误上。
请注意,由于缓冲等原因,命令的输出可能会交错标准输出和标准错误,这与它们在没有任何 I/O 重定向的情况下在终端屏幕上显示的方式不同。这几乎是不可避免的。如果你想避免它,你就会涉及到使用伪 ttys (ptys),这是一个复杂的领域,即使这样,如果你需要通过sed.
该脚本genouterr.sh只是生成标准输出和标准错误行:
#!/bin/bash
for i in {01..50}
do
echo "stdout $i"
echo "stderr $i" >&2
done
Run Code Online (Sandbox Code Playgroud)
我所做的原始测试(我在一两个月前写的,作为扩展另一个问题的练习)是寻找包含以 0 结尾的数字的标准错误行(使用grep);将其更改为sed脚本是一个瞬间的工作。
#!/bin/bash
set -x
rm -f out.[123]
./genouterr.sh 1>/dev/null
./genouterr.sh 2>/dev/null
( ./genouterr.sh 2>&1 1>&3 | grep '[0-9]0' >&2) 3>out.3 2>out.2 1>out.1
ls -l out.[123]
( ./genouterr.sh 2>&1 1>&3 | grep '[0-9]0' >&2) 3>&1
Run Code Online (Sandbox Code Playgroud)
当您运行此脚本时,您会发现该文件out.1是空的,包含写入标准输出的out.3内容,并包含写入标准错误的内容的过滤版本。genouterr.shout.2genouterr.sh