【问题标题】:while loop stops after first iteration in BASH [duplicate]在 BASH 中第一次迭代后,while 循环停止 [重复]
【发布时间】:2014-10-02 13:49:01
【问题描述】:

我编写了将 *.avi 文件转换为 mp4 格式的脚本。 然而,“while”循环在第一次迭代后停止。

#!/bin/bash
shopt -s lastpipe

cd <some_directory>

find . -name *.avi -type f |
  while read -r avi
    do
      /usr/bin/HandBrakeCLI -i "${avi}" -o "${avi%.avi}.mp4" -f mp4 -m -O -e x264 -q 20 --vfr \
#      &> /dev/null
      if [ "$?" -eq 0 ]
        then
          echo "${avi} was converted successfully"
          rm "${avi}"
        else
          echo "${avi} was not converted"
          break
      fi
    done 

【问题讨论】:

  • 你应该添加一个问题。
  • 因为break 声明?顺便说一句,使用done &lt; &lt;(find...)lastpipe 相同,并且它更常见。 :)

标签: bash while-loop do-while


【解决方案1】:

HandBrakeCLI 也可能正在读取输入,它使您的循环在第一个实例被调用后结束。由于您使用的是 bash,因此您可以使用进程替换并将输入重定向到另一个文件描述符。在这个例子中使用4:

while read -ru 4 avi; do
    ...
done 4< <(exec find . -name *.avi -type f)

我的首选版本也是使用readarray。如果您不针对带有换行符的不规则文件名,那就足够了:

readarray -t files < <(exec find . -name *.avi -type f)
for avi in "${files[@]}"; do
    ...
done

另一种方法可能是将HandBrakeCLI 的输入重定向到/dev/null

</dev/null /usr/bin/HandBrakeCLI ...

其他建议:

  1. 引用您的-name 模式:'*.avi'
  2. 使用IFS= 防止去除前导和尾随空格:IFS= while read ...

【讨论】:

    【解决方案2】:

    这部分错了:find . -name *.avi -type f

    shell 正在扩展通配符之前 find 开始,所以 find 命令看起来像:

    find . -name a.avi b.avi.c.avi d.avi ... -type f
    

    我很惊讶您没有注意到错误消息,例如“查找:路径必须在表达式之前:b.avi”

    您需要保护星号免受 shell 的影响,以便 find 可以自己扩展。选择一个

    find . -name \*.avi -type f
    find . -name '*.avi' -type f
    

    你没有提到你是否在 GNU 系统上。您的 while 循环有被带有前导或尾随空格的文件名绊倒的风险。试试这个:

    find . -name \*.avi -type f -print0 | while read -rd '' avi; do ...
    

    【讨论】:

    • 您忘记设置 IFS 以保持前导/尾随空格:而 IFS= read -rd '' avi;做...
    猜你喜欢
    • 2015-10-20
    • 1970-01-01
    • 2015-08-07
    • 2016-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    相关资源
    最近更新 更多