关于“ ls”的奇怪行为而在外壳脚本中使用ffmpeg读取时

时间:2018-12-13 07:13:37

标签: bash shell ffmpeg

我创建了一个Shell脚本,将所有wave文件转换为mp3文件。我使用Ubuntu 18.04,使用apt安装了FFmpeg,然后在bash中运行脚本。

我的脚本:

#!/bin/bash

ls *.wav | while read file
do
    echo $file
    ffmpeg -i "$file" -codec:a libmp3lame -b:a 192k "${file%.*}.mp3"
done

目标文件如下:(包括空格字符。实际文件名较长,但是我简化了文件名。在这种情况下,也会出现问题)

% ls *.wav
'01 A.wav'  '02 A.wav'  '03 A.wav'

问题在于,有时循环中的$ file是空白或文件名的一部分很奇怪('echo $ file'表明了这一点),而ffmpeg则说'[[破碎的文件名]:没有这样的文件或目录”。我确认了以下内容。

  • 当我注释掉ffmpeg行时,“ echo”显示了我的期望。 ($ file未损坏)
  • 当我将ffmpeg替换为类似“ lame”的类似命令时,它可以工作。 ($ file未损坏)
  • 当我替换'ls * .wav |读取文件”到“用于* .wav中的文件”时,它可以工作。 ($ file未损坏)

因此,仅当我使用'ls'和'ffmpeg'的组合时,$ file才损坏。这是怎么回事?还是我误会了什么?

1 个答案:

答案 0 :(得分:2)

您不应使用ls来传送文件列表,因为这种方法不适用于某些情况,例如文件名带有空格。

最易读的方式是使用 globbing

for file in *.wav
do
  echo "$file"
  ffmpeg -i "$file" -codec:a libmp3lame -b:a 192k "${file%.*}.mp3"
done

查找在这里也做得很好,但是最终您将得到一些不太易于维护的代码:

find -name *.wav -exec ffmpeg -i {} -codec:a libmp3lame -b:a 192k {}.mp3 \;

find示例将为您提供以.wav.mp3结尾的文件名而不是.mp3,如果要避免这种情况,则必须从find调用shell,从而允许您使用basename或执行类似${file.*}的操作(您必须首先在该shell中将find的{}分配给类似file的变量:

find -name "*.wav" -exec sh -c "file=\"{}\" ; ffmpeg -i \"\$file\" -codec:a libmp3lame -b:a 192k \${file%.*}.mp3" \;