【问题标题】:bash loop over files mysterious bugbash循环文件神秘的错误
【发布时间】:2019-07-17 14:29:27
【问题描述】:

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

这个:

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 的方式上并不明智。

【问题讨论】:

    标签: bash while-loop stdin mplayer


    【解决方案1】:

    使用mplayer-noconsolecontrols 选项。它使它忽略标准输入,因此它不会从中窃取字符,read 可以处理它们,mplayer 的行为并不奇怪,将文件名解释为来自键盘的命令。

    【讨论】:

      【解决方案2】:

      你的猜测是正确的。 find 将其文件列表输出到stdout。您将其输入到第二个进程:您的while 循环。在这个循环中,readmplayer 都从 stdin 读取。 read 将读取第一个文件名,mplayer 将读取所有其余输入,就像您在运行时通过键盘控制它一样。

      最简单的解决办法是在mplayer后面加上</dev/null,但是如果不能从stdin读取可能就不开心了。其他解决方案是为您的 find | read 部分使用单独的文件描述符,或者改用 for-loop。

      【讨论】:

      • 谢谢你,你是某种了不起的 bash 天才,我会尽快接受你的回答!
      • 不要将for 循环和YMMV 与find | read 一起使用,请参阅mywiki.wooledge.org/BashFAQ/001
      【解决方案3】:

      改为这样做:

      #!/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)
      

      http://mywiki.wooledge.org/BashFAQ/001

      【讨论】:

      • 9 是一个任意选择的文件描述符编号,该文件描述符(尚未)在其他地方使用。你可以选择任何你喜欢的数字,只要它是免费的,这主要意味着>2。
      • 对,我使用 9,因为 FAQ 使用 9,我希望 OP 能够清楚/轻松地看到 FAQ 解决方案如何应用于他的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      • 2013-09-16
      • 2014-06-07
      • 1970-01-01
      • 2015-03-13
      • 2017-04-20
      相关资源
      最近更新 更多