bash循环文件神秘bug

bash循环文件神秘bug,bash,while-loop,stdin,mplayer,Bash,While Loop,Stdin,Mplayer,谁能告诉我这里发生了什么 这: 就我所见,它工作得非常好,但是如果我真的尝试运行mplayer而不是响应命令: find . -name "*.mp3" | while read fname ; do echo "$fname"; ls "$fname"; mplayer "$fname" ; echo "$fname" ; done 然后它播放一个文件,然后失控 我认为mplayer一定是以某种方式与read交互的,但我对bash的方式并不明

谁能告诉我这里发生了什么

这:

就我所见,它工作得非常好,但是如果我真的尝试运行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
-noconsollecontrols
选项。它使它忽略了标准输入,因此它不会从中窃取字符,
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)
#/bin/env bash

虽然IFS=read-r-d“fname谢谢你,你是某种了不起的bash天才,我会尽快接受你的回答!不要将
用于
循环和带有
find | read
的YMMV,请参阅。
9
是一个任意选择的文件描述符编号,在其他地方尚未使用。你可以选择你喜欢的任何数字,只要是免费的,这主要意味着>2。对,我使用9是因为常见问题解答使用9,我希望OP能够清楚/轻松地看到常见问题解答解决方案如何应用于他的问题。
#!/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)