My script accepts a stream on stdin. I want to pass the first line through to stdout no matter what, and grep the remaining lines with -v
and also pass those out to stdout.
I worked out a solution using tee, but I'm wondering if this is guaranteed to always print the output of head
before the output of grep
? What if head
was replaced with something that blocked for 20 minutes before printing anything, would that output appear at the end of stdout after the output of grep
?
tee >(head -n 1) >(tail -n +2 | grep -v -E "$PATTERN")
If the order is not guaranteed, what is the right way of doing this?
You are overthinking this and you don't need tee
, head
or tail
.
You can consume the first line using read
and just print it out, then use grep
on the rest:
$ printf "foo\nbar\nquux\n" | { read v; echo "$v"; grep -v bar; }
foo
quux
Or, combining the logic into a single awk
statement and avoiding the problem altogether:
$ printf "foo\nbar\nquux\n" | awk 'NR==1{print;next} !/bar/'
foo
quux
You're right to be paranoid. The two sub-shells will run in parallel, so there's no guarantee that one will run before the other. To force an order of operations, read and print the first line before you grep the rest of the input.
read line && printf '%s\n' "$line"
tee >(grep -v -E "$PATTERN")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With