4

I'm struggling with this problem. I have this line:

mplayer *.* 2>/dev/null | grep Playing

which just launchs mplayer and only the line matching Playing filename is printed on screen. This works also every time I change currently played media.

I was wondering if it was possible to "format" the output of grep. For example, if the output is:

Playing Pink_Floyd-Wish_You_Were_Here.mp3  # I get this at the beginning
Playing Pearl_Jam-Once.mp3                 # I get this after I change media inside mplayer

then I would have something like:

Mplayer: Playing Pink_Floyd-Wish_You_Were_Here.mp3
Mplayer: Playing Pearl_Jam-Once.mp3

To do so, I decided to employ awk:

mplayer *.* 2>/dev/null | grep Playing | awk '{print "Mplayer: "$1}'

But in this case nothing happens; I get no output!!!

My question is not oriented to solve the problem with mplayer, but to have a deeper understanding about pipes in bash.

For example, if I use the following:

echo a_song.mp3 | awk '{print "Mplayer: "$1}'

I get what I want

Mplayer: a_song.mp3

Why does the first command not work?

What do I have to do if I want to run more than one process like this in background?

15
  • Did you have a single quote at the end of your first awk command?  What happens if you do mplayer *.* 2>/dev/null | grep Playing > foo and then awk '{print "Mplayer: "$1}' < foo?  Oh, BTW: $1 means just the first word, so I would expect you to get "Mplayer: Playing".  You probably want $0. Apr 25, 2015 at 18:04
  • Yes a single quote (the character '). I tried what you wrote. The obtained file foo is empty. Apr 25, 2015 at 18:07
  • What you need is mplayer Playing* 2>/dev/null | awk '/Playing/{print "Playing: " $0}' and you're done Apr 25, 2015 at 18:09
  • 1
    Well, that doesn't make any sense; if mplayer *.* 2>/dev/null | grep Playing produces output to the terminal, then redirecting it to a file should get that same output.  Now you know where the problem is, and so where to focus your investigation. Apr 25, 2015 at 18:10
  • 1
    @val0x00ff: “My question is not oriented to solve the problem with mplayer, but to have a deeper understanding …”  So, while mplayer *.* 2>/dev/null | awk '/Playing/ {print "Mplayer: " $0}' (note that you have two errors in your suggestion) will fix this particular problem, it doesn’t explain why the command he tried produced no output. Apr 25, 2015 at 18:14

1 Answer 1

6

Many grep implementation will use line buffered when standard output is terminal. When standard output is terminal, it's often an interactive session, you want to get data as soon as possible. So grep will write data to standard output as soon as seeing a newline.

When standard output isn't terminal (often meaning non-interactive session), grep will use block buffer instead. It means grep doesn't write to standard output immediately when seeing a newline. grep collects amount of data (4096 bytes in Linux) before writing to standard output.

Some grep version, like GNU grep or BSD grep have --line-buffered option. It make grep always writing to standard output when seeing a newline. So your example become:

mplayer *.* 2>/dev/null | grep --line-buffered Playing | awk '{print "Mplayer: "$1}'

If your grep version doesn't have --line-buffer, you can do it all with awk:

mplayer *.* 2>/dev/null | awk '/Playing/{print "Mplayer: "$1}'

GNU coreutils has a tool stdbuf for modifying buffering of command. You can always force line buffer in standard output with:

stdbuf -oL command

There's also unbuffer command which disables the output buffering only.

Further reading

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.