bashwhile-loopstdinmplayer

bash loop over files mysterious bug


Can anyone tell me what's going on here:

This:

find . -name "*.mp3" | while read fname ; do 
    echo "$fname"; 
    ls -l "$fname"; 
    echo mplayer "$fname" ; 
    echo "$fname" ;
done

works absolutely fine as far as I can see, but if I actually try to run mplayer instead of echoing the command:

find . -name "*.mp3" | while read fname ; do 
     echo "$fname"; 
     ls "$fname"; 
     mplayer "$fname" ; 
     echo "$fname" ; 
done

Then it plays one file and then goes haywire.

I'm thinking that mplayer must be interacting with read somehow, but I am not wise in the ways of bash.


Solution

  • Your guess is correct. find outputs its list of files to stdout. You pipe that in to a second process: your while loop. In this loop, both read and mplayer read from stdin. read will read the first filename, and mplayer will read all the rest of the input as if you were controlling it via the keyboard while running.

    The easiest solution is to add </dev/null after mplayer, but it may not be happy if it can't read from stdin. Other solutions are to use a separate file descriptor for your find | read part, or use a for-loop instead.