Reputation: 3694
I'm testing some netcat udp shell tools and was trying to take output and send it through standard pipe stuff. In this example, I have a netcat client which sends 'foo' then 'bar' then 'foo' with newlines for each attempt reading from the listener:
[root@localhost ~ 05:40:20 ]# exec 5< <(nc -d -w 0 -6 -l -k -u 9801)
[root@localhost ~ 05:40:25 ]# awk '{print}' <&5
foo
bar
foo
^C
[root@localhost ~ 05:40:48 ]# awk '{print}' <&5 | grep foo
^C
[root@localhost ~ 05:41:12 ]# awk '{print}' <&5 | grep --line-buffered foo
^C
[root@localhost ~ 05:41:37 ]#
[root@localhost ~ 05:44:38 ]# grep foo <&5
foo
foo
^C
[root@localhost ~ 05:44:57 ]#
I've checked the --line-buffered... and I also get the same behavior from 'od -bc', ie, nothing at all. Grep works on the fd... but if I pipe that grep to anything (like od -bc, cut), I get the same (nothing). Tried prefixing the last grep with stdbuf -oL to no avail. Could > to file and then tail -f it, but feel like I'm missing something.
Update:
Appears to be something descriptor/order/timing related. I created a file 'tailSource' and used this instead, which produced the same issue (no output) when I ran echo -e "foo\nfoo\nbar\nfoo" >> tailSource
[root@localhost shm 07:16:18 ]# exec 5< <(tail -n 0 -f tailSource)
[root@localhost shm 07:16:32 ]# awk '{print}' <&5 | grep foo
... and when I run without the '| grep foo', I get the output I'd expect. (GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu))
Upvotes: 1
Views: 557
Reputation: 6171
awk
is buffering when its output is not going to a terminal. If you have GNU awk, you can use its fflush() function to flush after every print
gawk '{print; fflush()}' <&5 | grep foo
In this particular case though, you don't need awk and grep, either will do.
awk /foo/ <&5
grep foo <&5
See BashFAQ 9 for more on buffering and how to work around it.
Upvotes: 2
Reputation: 3249
For what it's worth
$ exec 5< <(echo -e "foo\nbar\nfoo")
$ awk '{print}' <&5 | grep foo
prints
foo
foo
where as
$ exec 5< <(echo -e "foo\nbar\nfoo")
$ awk '{print}' <&5
foo
bar
foo
$ awk '{print}' <&5
$
the second call does not output anything.
I think this is because the file descriptor is at its end and you need to rewind it, see also this answer to this question question.
In order to use it, you could alternatively either capture it in a temporary file or perform the transformations in one line.
Upvotes: 2