while循环在BASH中的第一次迭代后停止

时间:2014-08-09 01:25:44

标签: bash while-loop do-while

我编写了必须将* .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 

2 个答案:

答案 0 :(得分:1)

这部分是错误的:find . -name *.avi -type f

shell在 find启动之前扩展通配符,因此find命令如下所示:

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

我很惊讶您没有注意到错误消息,例如“find:paths必须先于表达式:b.avi”

您需要保护星号不受外壳影响,因此可以找到自己的扩展名。选择其中一个

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

你没有提到你是否使用GNU系统。你的while循环有可能被带有前导或尾随空格的文件名绊倒。试试这个:

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

答案 1 :(得分:0)

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 ...