为什么在某些情况下我无法重定向输出

为什么在某些情况下我无法重定向输出

例如

# this line should output ssh banner
nc localhost 22
# this line should output the same string expect the replacements
nc localhost 22|sed 's/SSH/XXX/g'

nc localhost 22 > foo # after killing the process, I can see the banner in file `foo`
nc localhost 22|sed 's/SSH/XXX/g' > foo # however I see nothing when sed is used

如前所述,如果我使用sed管道传输nc的输出,则sed无法将 的输出重定向到文件。

我还尝试了其他命令来传递结果,例如grep, tr,相同的结果。

但是,cat可以将结果通过管道传输到文件。奇怪的..

nc localhost 22|cat > foo

那么为什么会发生这种情况呢?cat在这种情况下和其他命令有什么区别?我怎样才能将sed输出重定向到文件cat

答案1

$ 猫 | sed -e 's/foo/bar/' > 输出.txt
^C
$猫输出.txt
[没有什么]

但:

$ 猫 | sed -e 's/foo/bar/' > 输出.txt
^D
$猫输出.txt
酒吧

对文件的写入(但不是对终端)通常由 C 库(stdio 函数)缓冲到数千字节的块。如果您按 Ctrl-C 来终止管道,则sed在管道终止之前将没有时间写出缓冲区,因此生成的输出文件为空。(你可以说这是 C 库中的一个错误,它没有捕获终止信号,但事实就是如此。)

Plaincat可能不使用 stdio,因为它不处理任何复杂的东西,比如线条。类似的东西cat -n可能会有所不同,也可能不会。

您可以进行安排,以便不需要使用 Ctrl-C 终止管道,而是让它自行完成。至少在 my 中nc,该-qN选项告诉它在之后退出stdin 关闭后的秒数,因此例如:

$ printf '' | nc -q0 localhost 22 | sed 's/SSH/FOO/' > output.txt 
$ cat output.txt 
FOO-2.0-OpenSSH_7.4p1 Debian-10+deb9u7

或者,至少有几种方法可以关闭缓冲,请参见例如 关闭管道中的缓冲用于删除标准输出缓冲的“unbuffer”或“stdbuf”?

GNU sed 也有-u/--unbuffered开关

从输入文件加载最少量的数据并更频繁地刷新输出缓冲区

相关内容