In
dd if=/dev/zero bs=1024K count=1 | nc <IP_ADDR> <PORT> -q 0 | grep copied
there's no way that dd status output could go to grep. grep is reading the output of nc, not dd. If dd wrote that output on its stdout, it would go to nc, not grep.
Thankfully dd does not write that status message to its stdout (otherwise it would be sent to <IP_ADDR> which we don't want), but it writes it on a separated stream: stderr (as it's a diagnostic message, not part of its normal output).
To have dd's stderr connected to a pipe that goes to grep (and nc's stdout+stderr unchanged), you could do:
{ {
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
Assuming the shell's stdin/stdout/stderr go to I, O, E (all would be the tty device open in read+write mode if run from a terminal), in the above we would have:
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
Or to have the stderr of dd and the stdout+stderr of nc go to grep (but the stdout of dd still go to nc):
{
dd if=/dev/zero bs=1M count=1 |
nc -q 0 <IP_ADDR> <PORT>
} 2>&1 | grep copied
Our table of fd assignment per command becomes:
cmd \ fd | stdin stdout stderr
---------+--------------------
dd | I pipe1 pipe2
nc | pipe1 pipe2 pipe2
grep | pipe2 O E
Yet another approach:
{
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
But note that that output won't be very relevant. That 1MiB of data will probably fit in the pipe buffer, nc's internal read buffer and the socket send buffer, so you won't be really timing the network throughput. It's likely dd will return before the first data packet is sent over the network (shortly after the TCP connection has been enabled and nc starts reading its stdin). Look at iperf instead for that.
Without iperf, you could get a better measurement of sending throughput if you did something like:
{
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>