【问题标题】:passing script variable of filename with spaces in bash to external program (ffmpeg) fails将bash中带有空格的文件名脚本变量传递给外部程序(ffmpeg)失败
【发布时间】:2016-04-18 01:24:37
【问题描述】:

简短的故事:我正在尝试编写一个脚本,该脚本将使用 FFmpeg 将存储在一个目录中的许多文件转换为“标准”mp4 格式,并将转换后的文件保存在另一个目录中。这是一次学习经历(一次有趣的经历!),因为自从在 IBM 370 大型机上使用 Pascal 和 FORTRAN 很流行以来,我还没有进行任何真正的编码。

基本上,脚本获取文件名,去除路径和扩展名,用路径和 mp4 扩展名重新组合文件名,并使用一些设置参数调用 FFmpeg 进行转换。如果该目录仅包含名称中没有空格的视频文件,则一切正常。如果文件名包含空格,则 FFmpeg 无法处理该文件并继续处理下一个文件。该错误表明 FFMpeg 只能看到文件名直到第一个空格。我在下面包含了脚本和输出。

感谢您提供的任何帮助和建议。如果您认为我应该以另一种方式这样做,请务必给我您的建议。正如我所说,我已经很久没有做过这样的事情了。不过我很享受。

我首先包含代码,然后是示例输出。

for file in ./TBC/*.mp4
    do

    echo "Start of iteration"
    echo "Full text of file name:" $file

    #Remove everything up to  "C/" (filename without path)
    fn_orig=${file#*C/}
    echo "Original file name:" $fn_orig

    #Length of file name
    fn_len=${#fn_orig}
    echo "Filename Length:" $fn_len

    #file name without path or extension
    fn_base=${fn_orig:0:$fn_len-4}
    echo "Base file name:" $fn_base

    #new filename suffix
    newsuffix=".conv.mp4"

    fn_out=./CONV/$fn_base$newsuffix
    echo "Converted file name:" $fn_out

    ffmpeg -i $file -metadata title="$fn_orig" -c:v libx264 -c:a libfdk_aac -b:a 128k $fn_out

    echo "End of iteration"
    echo
    done
echo "Script completed"

注释掉 ffmpeg 行,./TBC 目录中有两个文件,这是我得到的输出

    Start of iteration
    Full text of file name: ./TBC/Test file with spaces.mp4
    Original filename: Test file with spaces.mp4
    Filename Length: 25
    Base filename: Test file with spaces
    Converted file name: ./CONV/Test file with spaces.conv.mp4
    End of iteration

    Start of iteration
    Full text of file name: ./TBC/Test_file_with_NO_spaces.mp4
    Original file name: Test_file_with_NO_spaces.mp4
    Filename Length: 28
    Base file name: Test_file_with_NO_spaces
    Converted file name: ./CONV/Test_file_with_NO_spaces.conv.mp4
    End of iteration

    Script completed

当 ffmpeg 未注释时,我不会费心发布结果,除了声明它因错误而失败: ./TBC/Test: 没有这样的文件或目录

然后脚本继续到下一个成功完成的文件,因为它的名称中没有空格。实际文件名是“Test file with spaces.mp4”,因此您可以看到 ffmpeg 在遇到空格时在“Test”一词后停止。

我希望这是清晰简洁的,希望有人能够为我指明正确的方向。我还想用这个脚本做很多事情,比如解析子目录和忽略非视频文件等。

我期待您提供任何见解!

【问题讨论】:

  • 提问时;让它最小化!这是太多的文字和代码来解决实际问题!
  • 你试过我的答案了吗?它奏效了吗?有更新吗?
  • 嗨,对不起……我去睡觉了,刚起床。我试过你的想法,但它仍然不起作用......没有运气。有什么想法吗?
  • 如我所问;你还有完全相同的错误吗?你的错误是什么?您可以使用bash -x <yourscript> 来调试导致问题的确切命令。
  • 是的,我仍然收到相同的错误,即:“./TBC/Test:没有这样的文件或目录”,因为它停止的文件的名称是“带有空格的测试文件。 mp4",它向我表明传递的参数(文件名)仅传递到第一个空格。脚本继续继续并成功处理目录中的第二个文件。该文件的名称不包含任何空格。

标签: macos bash ffmpeg


【解决方案1】:

还有另一种极端情况,空格会破坏 bash for 循环。

“BASH for 循环在 UNIX / Linux / Windows 和 OS X 下在处理文件集时可以很好地工作。但是,如果您尝试在文件名中处理带有空格的 for 循环,那么您就是会有一些问题。for循环使用$IFS变量来确定字段分隔符是什么。默认情况下$IFS设置为空格字符..."

https://www.cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html

之前:

for file in $(find . -name '*.txt'); do echo "$file"; done

输出:

./files/my
documents/item1.txt
./files/my
documents/item2.txt
./files/my
documents/item3.txt

因此,您应该将 IFS 设置为忽略空格。

之后:

IFS=$'\n'
for file in $(find . -name '*.txt'); do echo "$file"; done

输出:

./files/my documents/item1.txt
./files/my documents/item2.txt
./files/my documents/item3.txt

【讨论】:

    【解决方案2】:

    尝试引用你的输出文件:

    ffmpeg -i "$file" ... "$fn_out"
    

    bash 根据空格分隔参数,所以你必须告诉他 $fn_out 是一个单独的参数; "" 表明这是一个论点。

    【讨论】:

    • 即使在变量周围加上引号,文件名带空格的迭代仍然会在 FFmpeg 中引发错误。 The Quotes 似乎并没有把这个名字作为一个整体。有什么想法吗?
    • 确实是输入字段中缺少引号。我猜是因为它成功地从目录中读取了带有空格的文件,但没有将文件写入其中,所以当它一直是导致问题的输入参数时,我开始专注于输出。再次感谢您的帮助!
    猜你喜欢
    • 2020-11-02
    • 2015-11-13
    • 2017-01-10
    • 2015-05-09
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 2018-11-26
    相关资源
    最近更新 更多