Reputation: 17470
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.
Upvotes: 1
Views: 122
Reputation: 242103
Use the -noconsolecontrols
option of mplayer
. It makes it ignore the standard input, so it doesn't steal characters from it and read
can process them, and mplayer
doesn't behave strangely, interpreting file names as commands coming from the keyboard.
Upvotes: 4
Reputation: 204310
Do this instead:
#!/bin/env bash
while IFS= read -r -d '' fname <&9; do
printf '%s\n' "$fname"
ls "$fname"
mplayer "$fname"
printf '%s\n' "$fname"
done 9< <(find . -name '*.mp3' -print0)
See http://mywiki.wooledge.org/BashFAQ/001
Upvotes: 2
Reputation: 932
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.
Upvotes: 2