我使用以下命令通过 netcat 复制 dd 输出
$dd if=/dev/zero bs=1024K count=1 | nc <IP_ADDR> <PORT> -q 0
1+0 enregistrements lus
1+0 enregistrements écrits
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,0590934 s, 17,7 MB/s
但是,当我尝试解析输出时,没有任何反应
$ dd if=/dev/zero bs=1024K count=1 | nc <IP_ADDR> <PORT> -q 0 | grep copied
1+0 enregistrements lus
1+0 enregistrements écrits
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,058937 s, 17,8 MB/s
它应该只打印最后一行,为什么输出不发送到 grep?我尝试了几次重定向,但无法按照我的意愿对其进行重定向。
我希望通过 netcat 发送数据,但将输出消息(stderr 和 stdin)发送到 stdout 或文件以在之后解析它。
答案1
在
dd if=/dev/zero bs=1024K count=1 | nc <IP_ADDR> <PORT> -q 0 | grep copied
状态输出不可能dd
转到grep
.grep
正在读取 的输出nc
,而不是dd
。如果dd
将该输出写入其标准输出,它将转到nc
,而不是grep
。
值得庆幸的是,dd
它不会将该状态消息写入其标准输出(否则它将被发送到<IP_ADDR>
我们不想要的地方),而是将其写入一个单独的流:stderr(因为它是诊断消息,而不是其正常输出的一部分)。
要将 dd
'stderr
连接到一个通往grep
(并且nc
's stdout+stderr 不变)的管道,您可以这样做:
{ {
dd if=/dev/zero bs=1M count=1 2>&3 3>&- |
nc -q 0 <IP_ADDR> <PORT> 3>&-
} 3>&1 >&4 4>&- | grep copied 4>&-; } 4>&1
假设 shell 的 stdin/stdout/stderr 转到I
, O
, E
(如果从终端运行,所有这些都将以读+写模式打开 tty 设备),在上面我们将有:
cmd \ fd | stdin stdout stderr 3 4
---------+------------------------------------
dd | I pipe1 pipe2 closed closed
nc | pipe1 O E closed closed
grep | pipe2 O E closed closed
或者让 stderrdd
和 stdout+stderrnc
转到grep
(但 dd 的 stdout 仍然转到 nc):
{
dd if=/dev/zero bs=1M count=1 |
nc -q 0 <IP_ADDR> <PORT>
} 2>&1 | grep copied
每个命令的 fd 分配表变为:
cmd \ fd | stdin stdout stderr
---------+--------------------
dd | I pipe1 pipe2
nc | pipe1 pipe2 pipe2
grep | pipe2 O E
还有另一种方法:
{
dd if=/dev/zero bs=1M count=1 2>&1 >&3 3>&- |
grep copied >&2 3>&-
} 3>&1 | nc -q 0 <IP_ADDR> <PORT>
cmd \ fd | stdin stdout stderr 3
---------+-----------------------
dd | I pipe1 pipe2
nc | pipe1 O E
grep | pipe2 E E
但请注意,该输出不会非常相关。这 1MiB 的数据可能适合管道缓冲区、nc
内部读取缓冲区和套接字发送缓冲区,因此您不会真正计时网络吞吐量。它很可能dd
会在第一个数据包通过网络发送之前返回(在启用 TCP 连接并nc
开始读取其标准输入后不久)。看看iperf
相反的。
如果没有iperf
,您可以通过执行以下操作来更好地测量发送吞吐量:
{
dd bs=1M count=50 2> /dev/null # buffers filled and the TCP connection
# established and into a steady state
dd bs=1M count=100 2>&1 >&3 3>&- | grep copied >&2 3>&-
} < /dev/zero 3>&1 | nc -q 0 <IP_ADDR> <PORT>