【问题标题】:Batch File: Escaping ! within For Loop批处理文件:逃跑!在 For 循环内
【发布时间】:2017-04-16 04:34:38
【问题描述】:

我正在尝试创建一个 for 循环,该循环将遍历一个目录并对该目录中的所有文件运行 ffmpeg 命令。我的问题是某些文件的名称中有!,这在使用延迟扩展时会导致问题。我研究了许多解决方案,但没有一个能帮到我。目前我可以回显包含! 的文件名,但我似乎无法将包含! 的文件名传递到我的for 循环中,因为延迟扩展有效地删除了!

这是我的批处理脚本:

@echo off
setlocal enabledelayedexpansion
for %%f in ("Y:\Samples\Test Videos\*.mkv") do (
    set "filename=%%~nxf"
    ffmpeg -i "%%f" -vcodec copy -acodec copy -scodec copy -vbsf h264_changesps=level=40 -vbsf h264_changesps=fps=24000:1001 "E:\Converted\!filename!"
)
pause

这适用于名称中没有! 的所有文件。如果我使用这样的批处理脚本:

@echo off
for %%f in ("Y:\Samples\Test Videos\*.mkv") do (
   call :command "%%f"
)
pause

:command
set "fname=%~nx1"
set "fpath=%~dpnx1"
echo %fname%
ffmpeg -i %fpath% -vcodec copy -acodec copy -scodec copy -vbsf h264_changesps=level=40 -vbsf h264_changesps=fps=24000:1001 "E:\Converted\%fname%"

然后我可以获取文件名和完整路径以回显包含!,但引用%fname%%fpath% 的ffmpeg 命令返回No such file or directory 消息。如果我在 echo 关闭后添加 SetLocal EnableDelayedExpansion 并将 ffmpeg 字符串更改为 ! 而不是 %,那么我再次收到 No such file or directory 消息。

我知道在 FOR 循环中,语句的 DO 部分中的所有内容都会在其他所有内容之前扩展,这就是我需要使用延迟扩展的原因,但是我怎样才能使用它并且仍然使用包含的文件名!?有没有办法让第一批接受名称中包含 ! 的文件?

【问题讨论】:

    标签: batch-file for-loop cmd escaping


    【解决方案1】:

    最简单的解决方案是不使用延迟扩展。

    @echo off
        setlocal enableextensions disabledelayedexpansion
        set ffmpegArguments=-vcodec copy -acodec copy -scodec copy -vbsf h264_changesps=level=40 -vbsf h264_changesps=fps=24000:1001
    
        for %%f in ("Y:\Samples\Test Videos\*.mkv") do (
            ffmpeg -i "%%f" %ffmpegArguments% "E:\Converted\%%~nxf" 
        )
        pause
    

    不需要将从for可替换参数中检索到的信息分配给变量,只需使用检索到的值即可

    【讨论】:

    • 你忘了说不需要CALL。 CALL 将破坏任何包含^ 的名称。您的代码应该适用于所有情况。
    • 出色的工作 MC ND!这很简单,事后看来很有意义!
    【解决方案2】:
    :command
    
    SETLOCAL DISABLEDELAYEDEXPANSION
    
    set "fname=%~nx1"
    set "fpath=%~dpnx1"
    echo %fname%
    ffmpeg -i %fpath% -vcodec copy -acodec copy -scodec copy -vbsf h264_changesps=level=40 -vbsf h264_changesps=fps=24000:1001 "E:\Converted\%fname%"
    
    ENDLOCAL
    GOTO :EOF
    

    应该通过禁用延迟扩展来解决您的问题,而 ! 是一个文字字符。

    我出于习惯添加了goto,所以如果我添加一个新的子例程,我就不必记住它。

    【讨论】:

    • 你的不起作用,因为%fpath% 需要用引号括起来,"%fpath%"。对我来说有趣的是,您的答案仅与我的不同,添加了DisableDelayedExpansion,但事实证明它甚至不需要。我只需将%fpath% 放在引号中即可使其正常工作。问题解决了!
    【解决方案3】:

    我发的太早了!我终于搞定了!

    事实证明,在第二个脚本中,使用 %fpath% 作为 ffmpeg 输入只会获取文件路径,直到它被截断的第一个空格(因为我没有将它放在引号中)。将%fpath% 放在引号中后,该脚本将适用于名称中包含! 的文件!这里是:

    @echo off
    for %%f in ("Y:\Samples\Test Videos\*.mkv") do (
       call :command "%%f"
    )
    
    :command
    set "fname=%~nx1"
    set "fpath=%~dpnx1"
    ffmpeg -i "%fpath%" -vcodec copy -acodec copy -scodec copy -vbsf h264_changesps=level=40 -vbsf h264_changesps=fps=24000:1001 "E:\Converted\%fname%"
    

    【讨论】:

    • 您设法修复了代码,但我认为您不完全理解原因。是的,您必须引用 "%fpath%",但如果值可能包含 !,则当您的 FOR 循环扩展 %%f 时禁用延迟扩展也很重要。默认是禁用延迟扩展,但您的原始代码已启用它。您在此答案中的代码有效,因为您没有启用延迟扩展。
    • 你仍有失败的可能。如果文件路径包含 ^ 字符,则 CALL 会将引用的 ^ 加倍为 ^^,您的命令将失败。 MC ND has a correct answer 应该适用于所有情况 - 没有延迟扩展、没有 CALL 和正确引用的参数。
    猜你喜欢
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2012-07-30
    • 2013-10-07
    • 2023-03-27
    • 1970-01-01
    • 2014-08-24
    • 2023-03-21
    相关资源
    最近更新 更多