1

I've gotten into an interesting state on Ubuntu. The steps below describe it the best.

With a single pipe, I'm seeing what I expect

# In shell A
tail -f foo.log | grep aaa

# In shell B
echo aaa >> foo.log

# Shell A prints out `aaa`

But with multiple pipes I'm not seeing anything at all

# In shell A
tail -f foo.log | grep aaa | grep bbb

# In shell B
echo aaa bbb >> foo.log

# Nothing ever prints in shell A

But it works fine if I'm just echoing.

echo 'aaa bbb' | grep aaa | grep bbb

This is my attempt to create a minimal reproduction -- I originally encountered the issue trying to tee logs from adb logcat (Android dev tools). I've tried in zsh, bash, and fish as well.

I assumed it has something to do with my inotify watcher limit but bumping it didn't change anything.

1 Answer 1

4

This is because of buffering in the pipe, which in general doesn't care about lines and can accumulate data.

I think tail -f uses line buffering by itself; and the last grep writes to the tty, so it also uses line buffering. Therefore your first example works.

But grep in the middle is different and you need to adjust its behavior by forcing line buffering or by disabling buffering. The bellow commands will work as you expected.

  • If your grep supports --line-buffered (it does in Ubuntu):

      tail -f foo.log | grep --line-buffered aaa | grep bbb
    
  • More generic solutions (they will work with many filters other than grep):

      tail -f foo.log | unbuffer -p grep aaa | grep bbb
      tail -f foo.log | stdbuf -oL grep aaa | grep bbb
      tail -f foo.log | stdbuf -o0 grep aaa | grep bbb
    

See man 1 grep, man 1 unbuffer and man 1 stdbuf for details and quirks.

Notes:

  • Neither solution is portable (grep --line-buffered, unbuffer and stdbuf are not specified by POSIX).
  • If you can do this with grep --line-buffered then it should be your choice. There's no point in using extra tools.
  • Related question on Unix & Linux SE: Turn off buffering in pipe.
  • unbuffer and stdbuf work in completely different ways.
  • With stdbuf, line buffering (-oL) should be preferred over no buffering (-o0) here, because
    • it most likely performs better,
    • and other parts of your pipe use line buffering anyway.
  • If your last grep wrote to yet another file, it would behave like the other grep. In such case if you want lines to appear in the final file immediately, then you should also modify the behavior of the last grep.
  • In fish, if grep is a wrapper function, you may not get the desired behavior with --line-buffered. Use command grep --line-buffered. See this question: Output pipe waits for EOF in fish.

Side note: tail foo.log | grep aaa | grep bbb (i.e. tail without -f) does not cause the issue because tail exits. When tail exits, the first grep detects EOF, flushes its buffer and exits, then the second grep does the same.

5
  • Thanks for the suggestion. In testing it I got a new piece of information. It actually works just fine in zsh, I'm not sure what changed from my last test, but it looks like its only a problem in fish, and there the --line-buffered switch actually doesn't do anything it seems. This might be a fish question. Commented Aug 16, 2019 at 19:32
  • EDIT: I do need the line-buffered options get it working isntantly in zsh as well, my bad. But I can't get that solution to work in fish. Commented Aug 16, 2019 at 19:35
  • Ok, this was the solution, thank you. The tricky part was fish's function wrapper around grep: unix.stackexchange.com/questions/305261/…. If I use grep directly with /bin/grep it works in fish as well. Not sure why they wrapped it. Commented Aug 16, 2019 at 19:46
  • @AnthonyNaddeo Thanks for the feedback. I integrated your observations and the link into my answer. Commented Aug 16, 2019 at 21:01
  • Great answer and special thanks for mentioning that unbuffer and stdbuf do technically totally different things as explained in unix.stackexchange.com/a/97327/20336unbuffer doesn't actually change buffering so it could have name like pretend-connected-to-terminal to better describe what it actually does. Commented Sep 28, 2022 at 8:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .