为何mplayer会退出Bash循环?脚本运行异常求助
我之前也踩过这个坑!问题的核心在于mplayer会默认抢占while循环的标准输入(stdin),你为了让find管道的while循环能接收用户输入做的重定向,刚好和mplayer的输入处理逻辑冲突了。咱们一步步拆解解决:
为什么会出问题?
当你用find ... | while read file这种管道结构时,while循环的stdin其实是来自find的输出管道。这时候在循环里运行mplayer,它会默认读取stdin——要么把管道里剩下的视频文件名当成输入吃掉,要么报错退出后搞乱stdin状态,导致while循环没法继续读取下一个文件。而mpv默认不会主动读取stdin,所以能正常运行,但你必须用mplayer的话,就得从输入重定向入手把两者的输入隔离开。
具体解决方案
方案1:用进程替换代替管道(最推荐)
把管道换成进程替换,让while循环的stdin保持为终端(而非find的输出管道),这样mplayer和用户输入的read都能正常工作:
while read -r file; do echo "正在播放: $file" # 让mplayer读取终端输入(如果需要交互控制的话),不需要交互可换成< /dev/null mplayer "$file" < /dev/tty # 播放完成后等待用户输入再继续 read -p "播放完成,按回车继续下一个..." done < <(find /你的视频目录 -type f -name "*.你的视频格式")
这里的< <(find ...)是bash的进程替换特性,相当于把find的输出写到临时文件,while循环从临时文件读取路径,而它的stdin还是你的终端,完全不会和mplayer抢输入。
方案2:显式绑定文件描述符
如果你一定要用管道,可以把find的输出绑定到额外的文件描述符(比如fd3),让while循环从fd3读路径,stdin留给终端:
# 把find的输出绑定到文件描述符3 exec 3< <(find /你的视频目录 -type f -name "*.你的视频格式") while read -u3 -r file; do echo "正在播放: $file" mplayer "$file" < /dev/tty read -p "按回车继续..." done # 用完后关闭文件描述符3 exec 3<&-
额外优化:无交互场景
如果播放过程中不需要手动控制mplayer,直接让它播放完退出,可以把mplayer的stdin重定向到/dev/null,彻底避免它读取任何输入:
mplayer "$file" < /dev/null
为什么mpv没问题?
mpv默认会把stdin重定向到/dev/null(或者它的输入处理逻辑不会主动读取stdin),所以不会去抢while循环的管道输入,自然能正常跑完循环。而mplayer默认会读取stdin,这才是冲突的根源。
内容的提问来源于stack exchange,提问作者Sandra Schlichting

