使用 "find" 和 "avconv" 转换多个递归视频文件

Convert multiple recursive video files using "find" and "avconv"

为了将目录中的 MOV 文件转换为 mp4,我使用了(我使用更多命令与 avconv,但我缩短了 syntetize):

for f in *.MOV; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done

并且有效。它转换每个文件。

但是现在,我想转换目录和所有子目录中的所有文件(递归)。我试过了:

for f in "$(find ./ -name '*.MOV')"; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done

但它不起作用,因为它输出:

mario@circo3d:~/Imágenes$ for f in "$(find ./ -name '*.MOV')"; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done
Converting ./2015-05-23 Tutorial Masa de colores/MVI_9219.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9196.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9199.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9200.MOV
avconv version 9.18-6:9.18-0ubuntu0.14.04.1, Copyright (c) 2000-2014 the Libav developers  built on Mar 16 2015 13:19:10 with gcc 4.8 (Ubuntu 4.8.2-19ubuntu1)
./2015-05-23 Tutorial Masa de colores/MVI_9219.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9196.MOV
./2015-05-23 Tutorial Masa de colores/MVI_9199.MOV
mario@circo3d:~/Imágenes$ 

(最后一个文件列表显示为红色)

似乎 find 有效,它进入每个目录并且 echo "Converting $f" 也...但是 avconv 收到所有文件名都是带有换行符的列表,而不是 "for" 循环中的每个元素。

为什么 echo 有效而 avconv 无效?

或者...

为什么 for f in *.MOV' 使用 avconv 而 for f in "$(find ./ -name '*.MOV') 不是吗?

这是因为您将它们放在引号中。在 POSIX 中,换行符可以很好地出现在文件名中。

最简单的解决方案是使用 find 的 -exec 属性重写:

find . -name "*.MTS" -exec echo {}  \; -exec avconv -i {} {}.mp4 \;

或者更好的是,您可以在 avconv 行中使用 -execdir,它将从找到文件的目录中执行命令。


从您的评论中,我发现您很难看出换行符的来源。所以

来自 find 的手册页:

If no expression is given, the  expression  -print  is  used

-print True; print the full file name on the standard output,  followed
       by  a  newline.

所以 find 实际上会为您打印所有换行符。您通过 $(find ...) 调用它,然后将其放在引号中,这意味着所有换行符都保留为常规字符。

这就是为什么您的 for 循环只执行一次的原因。

如果你绝对必须使用循环,而不是使用 find 自己的执行,你可能想要使用 while 循环:

find . -name "*.MTS" | while read f; do echo "Converting $f"; avconv -i "$f" "${f:0: -4}.mp4"; done

我使用 sox 将 mp3 转换为 alaw 文件。非常相似的情况。使用简单的 bash 脚本。

#!/bin/bash

for file in $(find . -name '*.mp3')
do
    echo $file
    sox $file -t al -c 1 -r 8000 $(echo "$file" | sed -r 's|.mp3|.alaw|g')
done