bash 循环文件神秘错误
bash loop over files mysterious bug
谁能告诉我这是怎么回事:
这个:
find . -name "*.mp3" | while read fname ; do
echo "$fname";
ls -l "$fname";
echo mplayer "$fname" ;
echo "$fname" ;
done
据我所知工作得很好,但如果我真的尝试 运行 mplayer 而不是回显命令:
find . -name "*.mp3" | while read fname ; do
echo "$fname";
ls "$fname";
mplayer "$fname" ;
echo "$fname" ;
done
然后它播放了一个文件,然后就乱七八糟了。
我认为 mplayer 必须以某种方式与 read 交互,但我在 bash 的方式上并不明智。
你猜对了。 find
将其文件列表输出到 stdout
。您将其通过管道传输到第二个进程:您的 while
循环。在这个循环中,read
和 mplayer
都从 stdin
读取。 read
将读取第一个文件名,mplayer
将读取所有其余输入,就好像您通过键盘控制它一样,而 运行.
最简单的解决办法是在mplayer后面加上</dev/null
,但是如果不能从stdin
读取它可能会不高兴。其他解决方案是为 find | read
部分使用单独的文件描述符,或者使用 for
循环。
使用 mplayer
的 -noconsolecontrols
选项。它使它忽略标准输入,所以它不会从中窃取字符并且 read
可以处理它们,并且 mplayer
不会表现得很奇怪,将文件名解释为来自键盘的命令。
改为这样做:
#!/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)
谁能告诉我这是怎么回事:
这个:
find . -name "*.mp3" | while read fname ; do
echo "$fname";
ls -l "$fname";
echo mplayer "$fname" ;
echo "$fname" ;
done
据我所知工作得很好,但如果我真的尝试 运行 mplayer 而不是回显命令:
find . -name "*.mp3" | while read fname ; do
echo "$fname";
ls "$fname";
mplayer "$fname" ;
echo "$fname" ;
done
然后它播放了一个文件,然后就乱七八糟了。
我认为 mplayer 必须以某种方式与 read 交互,但我在 bash 的方式上并不明智。
你猜对了。 find
将其文件列表输出到 stdout
。您将其通过管道传输到第二个进程:您的 while
循环。在这个循环中,read
和 mplayer
都从 stdin
读取。 read
将读取第一个文件名,mplayer
将读取所有其余输入,就好像您通过键盘控制它一样,而 运行.
最简单的解决办法是在mplayer后面加上</dev/null
,但是如果不能从stdin
读取它可能会不高兴。其他解决方案是为 find | read
部分使用单独的文件描述符,或者使用 for
循环。
使用 mplayer
的 -noconsolecontrols
选项。它使它忽略标准输入,所以它不会从中窃取字符并且 read
可以处理它们,并且 mplayer
不会表现得很奇怪,将文件名解释为来自键盘的命令。
改为这样做:
#!/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)