1
votes

I am trying to create a for loop that will go through a directory and run an ffmpeg command to all files within that directory. My problem is that some of the files have ! in their name which causes problems when using delayed expansion. I have researched many solutions and none of them are getting me anywhere. Currently I can echo the file names with the ! included, but I cannot seem to pass the file name with the ! into my for loop as the delayed expansion effectively removes the !.

Here is my batch script:

@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

This works fine for all files without the ! in the name. If I use a batch script like this:

@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%"

Then I can get the file names and full paths to echo with the ! included, but the ffmpeg command referencing %fname% and %fpath% returns a No such file or directory message. If I add in SetLocal EnableDelayedExpansion just after the echo off and change the ffmpeg string to have ! instead of %, then I again get the No such file or directory message.

I know that in a FOR loop everything in the DO part of the statement gets expanded before everything else which is why I need to use delayed expansion, but how can I use that and still use file names that contain !? Is there a way to get the first batch to accept files that have the ! in the name?

3

3 Answers

5
votes

The simplest solution is not to use delayed expansion.

@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

There is not any need to assign the information retrieved from the for replaceable parameter to a variable, just use the retrieved value

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

should fix your problem by disabling the delayedexpansion while ! is a literal character.

I add the goto out of habit so I don't have to remember about it if I add a new subroutine.

0
votes

I posted too soon! I finally got it working!

It turns out that in the second script using %fpath% for the ffmpeg input only gets the filepath up until the first space where it truncates (because I didn't have it in quotes). After putting %fpath% in quotes, the script works with files that have ! in the name! Here it is:

@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%"