grep with continuous pipe does not work
I think the problem is because of stdio buffering
, you need to use GNU stdbuf
before calling grep
,
sudo tcpflow -p -c -i eth0 port 80 2>/dev/null | stdbuf -o0 grep '^Host: '
With the -o0
, it basically means the output (stdout
) stream from tcpflow
will be unbuffered. The default behavior will be to automatically buffer up data into 40961 byte chunks before sending to next command in pipeline, which is what overriden using stdbuf
1. Refer this nice detail into the subject.
Piping of grep is not working with tail?
grep
is buffering it's output. To tell GNU grep to spit out output line-by-line you need to use --line-buffered
option in grep
to make it work:
tail -f eclipse.log | grep --line-buffered 'enimation' | grep --line-buffered -i 'tap'
As per man grep
:
--line-buffered
Force output to be line buffered. By default, output is line buffered when standard
output is a terminal and block buffered otherwise.
How to 'grep' a continuous stream?
Turn on grep
's line buffering mode when using BSD grep (FreeBSD, Mac OS X etc.)
tail -f file | grep --line-buffered my_pattern
It looks like a while ago --line-buffered
didn't matter for GNU grep (used on pretty much any Linux) as it flushed by default (YMMV for other Unix-likes such as SmartOS, AIX or QNX). However, as of November 2020, --line-buffered
is needed (at least with GNU grep 3.5 in openSUSE, but it seems generally needed based on comments below).
Unable to pipe output after grep
For grepping stream (tail -f
)
it's almost always better to use grep --line-buffered
instead of just grep
From official docs:
--line-buffered Use line buffering on output. This can cause a performance penalty.
In other words: Write output each time when grep get input and do not wait for filling grep buffer
bash: pipe continuously into a grep
What's Going Wrong
The code: if grep patternB; then echo "true"; fi
...waits for grep patternB
to exit, which will happen only when the input from tail -f file.log | grep patternA
hits EOF. Since tail -f
waits for new content forever, there will never be an EOF, so your if
statement will never complete.
How To Fix It
Don't use grep
on the inside of your function. Instead, process content line-by-line and use bash's native regex support:
customGrepFunction() {
while IFS= read -r line; do
if [[ $line =~ patternB ]]; then
echo "True"
fi
done
}
Next, make sure that grep
isn't buffering content (if it were, then it would be written to your code only in big chunks, delaying until such a chunk is available). The means to do this varies by implementation, but with GNU grep, it would look like:
tail -f file.log | grep --line-buffered patternA | customGrepFunction
No output while piping tail through grep
grep
is not line-buffered when its stdout isn't connected to a tty. So it's trying to process a block (usually 4 KiB or 8 KiB or so) before generating some output.
You need to tell grep
to buffer its output by line. If you're using GNU grep, this works:
done < <(tail -F -n +1 "$filepath" | grep '^!' --line-buffered)
^^^^^^^^^^^^^^^
How to process continuous stream output with grep utility?
As suggested by @larsks , " --line-buffered flush output on every line" option for grep is working fine when is test for similar requirement as yous .
So the command would be
curl -X "POST" "http://localhost:8088/query" --header "Content-Type: application/json" -d $'{"ksql": "select * from SENSOR_S EMIT CHANGES;","streamsProperties": {"ksql.streams.auto.offset.reset": "earliest"}}' -s -N | grep S1 --line-buffered | xargs -I {} echo {}
I tested on "/var/log/messages" file which gets continously updated as following :
[root@project1-master ~]# tail -f /var/log/messages | grep journal --line-buffered | xargs -I {} echo {}
Sep 11 11:15:47 project1-master journal: I0911 15:15:47.448254 1 node_lifecycle_controller.go:1429] Initializing eviction metric for zone:
Sep 11 11:15:52 project1-master journal: I0911 15:15:52.448704 1 node_lifecycle_controller.go:1429] Initializing eviction metric for zone:
Sep 11 11:15:54 project1-master journal: 2020-09-11 15:15:54.006 [INFO][46] felix/int_dataplane.go 1300: Applying dataplane updates
Why no output is shown when using grep twice?
You might also run into a problem with grep buffering when inside a pipe.
ie, you don't see the output from
tail --follow=name file.txt | grep something > output.txt
since grep will buffer its own output.
Use the --line-buffered switch for grep to work around this:
tail --follow=name file.txt | grep --line-buffered something > output.txt
This is useful if you want to get the results of the follow into the output.txt file as rapidly as possible.
Related Topics
How to Send a Sequence of at Commands to a Serial Port in Bash
If I Have a Process, and I Clone It, Is the Pid the Same
How to Remove Specific Rules from Iptables
How to Extract Filename.Tar.Gz File
How to Install SQL * Plus Client in Linux
How to Statically-Link a Complex Program
How to Signal an Application Without Killing It in Linux
How to Find the Processor/Chip Architecture on Linux
How to Get Cmake to Use the Default Compiler on System Path
Different Results Between Ps Aux and 'Ps Aux' Inside a Script
Ftdi D2Xx Conflict with Ftdi_Sio on Linux - How to Remove Ftdi_Sio Automatically
Deleting String Up to the First Occurrence of Certain Character