2017-04-16 60 views
1

我正在尝试创建一个for循环,它将通过一个目录并对该目录中的所有文件运行ffmpeg命令。我的问题是某些文件的名称中有!,这在使用延迟扩展时会导致问题。我研究了许多解决方案,其中没有一个能够让我找到任何地方。目前我可以使用包含的!来回显文件名,但我似乎无法通过!将文件名传递到我的for循环中,因为延迟扩展有效地删除了!批处理文件:转义!在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%" 

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

我知道,在声明的DO部分FOR环路一切都得到一切这就是为什么我需要使用延迟扩展前扩大,但我该如何使用,并仍在使用包含!文件名?有没有办法让第一批接受名称中包含!的文件?

回答

5

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

@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替换参数变量检索到的信息,只需使用检索到的值

+0

你忘了提及没有需要CALL。 CALL会破坏包含'^'的任何名称。你的代码应该适用于所有情况。 – dbenham

+0

出色的工作MC ND!这很简单,后见之明很有意义! – Trevor

0
: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 

应通过禁用delayedexpansion而!是文字字符解决您的问题。

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

+0

您的不起作用,因为'%fpath%'需要加引号,''%fpath%“'。对我来说有趣的是,你的答案与我在'DisableDelayedExpansion'中添加的内容不同,但事实证明它甚至不需要。我只需将'%fpath%'放在引号中即可。问题解决了! – Trevor

0

我发帖太快了!我终于搞定了!

事实证明,在使用%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%" 
+0

你设法修复你的代码,但我不认为你完全理解为什么。是的,你必须引用'“%fpath%”',但是当你的FOR循环展开'%% f'时,如果该值可能包含'!',那么延迟扩展也是关键的。默认是禁用延迟扩展,但您的原始代码已启用。此答案中的代码可用,因为您不启用延迟扩展。 – dbenham

+1

你仍然有失败的可能性。如果文件路径包含'^'字符,则CALL会将引用的^ ^加倍到'^^',并且您的命令将失败。 [MC ND有一个正确的答案](http://stackoverflow.com/a/43435510/1012053)应该在所有情况下工作 - 没有延迟扩展,没有CALL和正确引用的参数。 – dbenham