Batch file 将FOR循环通过GOTO循环传递到新命令提示符时出现问题

Batch file 将FOR循环通过GOTO循环传递到新命令提示符时出现问题,batch-file,Batch File,这是我的第一篇帖子,如果我解释得不好,我向你道歉。请让我知道我是否应该重新措辞或澄清一些事情!我对标题也不是很在行,所以如果我需要更改,请告诉我 为了帮助自己解释更多的情况,我想澄清一下这是为了什么。作为我的爱好之一,我帮助建立一个图像档案。它的一个问题是它支持的唯一视频格式是webm。这有时会导致不知道如何转换的用户无法正确转换低质量的视频,这需要稍后修复 正因为如此,我一直在处理一系列批处理文件,通过最小化所需的用户输入,这些文件既可以加快转换速度,也可以降低转换不良的视频数量。如果您想:

这是我的第一篇帖子,如果我解释得不好,我向你道歉。请让我知道我是否应该重新措辞或澄清一些事情!我对标题也不是很在行,所以如果我需要更改,请告诉我

为了帮助自己解释更多的情况,我想澄清一下这是为了什么。作为我的爱好之一,我帮助建立一个图像档案。它的一个问题是它支持的唯一视频格式是webm。这有时会导致不知道如何转换的用户无法正确转换低质量的视频,这需要稍后修复

正因为如此,我一直在处理一系列批处理文件,通过最小化所需的用户输入,这些文件既可以加快转换速度,也可以降低转换不良的视频数量。如果您想:

其中一位工作人员提到,他们希望有一种方法可以同时启动多个转换,并让它转换整个文件夹,因为他们的CPU足够强大。这就是我几天来一直在做的

我目前的脚本问题是,我似乎无法可靠地将FOR循环传递给新命令,并以任何方式提示它在GOTO循环中启动

我不介意重写当前脚本,只要它仍然能够使用FOR循环及其指定值启动多个ffmpeg实例

解决方案最好采用批处理或PowerShell脚本的形式,尽管任何其他语言也可以,只要它可以与批处理文件一起工作

我尝试了以下方法:

在GOTO循环中使用FOR循环启动cmd,方法是:

start cmd.exe <FOR loop>

预期的输出是脚本启动x个新命令提示,每个提示使用脚本中定义的相同FOR循环,并使用指定的输入、输出和将来的选择,例如编解码器。

我希望这能有所帮助。它可能需要应用一些修改。根据主帖子中的编辑,我根据
-n
更改了开关
-y

@echo off

setlocal EnableDelayedExpansion

:Pre_Main
::How many instances should be initiated. Limit hardcoded to 11.
::Input dir , Output dir.
set /p input=Input:
set /p output=Output:
set /p amount=Amount:

REM If not defined %amount% (
    REM echo Please specify a number of instances greater than 0
    REM goto :Pre_Main
REM )

if %amount% LEQ 0 (
    echo Please specify a number of instances greater than 0
    goto :Pre_Main
)

cd input

if exist ffmpeg_temp_files (
    rd /s /q ffmpeg_temp_files
) ELSE (
    md ffmpeg_temp_files
)

set "n_loop=1"

::
::End-Pre_Main
::

:loop
for %%f in (*) do (
    @echo on
    echo inside the loop... File: %%f n_loop: !n_loop!
    start "!n_loop!...%%f" ffmpeg.exe -n -i "%%f" -c:v vp9 -c:a libopus -crf 20 -b:v 192 -pix_fmt yuv420p -pass 1 -f webm "temp files\%%~nf_!time!_!n_loop!" && ffmpeg.exe -n -i "%%f" -c:v vp9 -c:a libopus -crf 20 -b:v 192 -an -pix_fmt yuv420p -pass 2 %output%\%%~nf.webm
    @echo off

    if !n_loop! GEQ !amount! goto :Pos_Main
    if !n_loop! EQU 12       goto :Pos_Main
    set /a n_loop=!n_loop!+1
)

:Pos_Main

endlocal

if exist ffmpeg_temp_files rd /s /q ffmpeg_temp_files
del /q /f ffmpeg2pass*

cd ..

choice /c EC /n /m "(E)xit or (C)ontinue"
if %errorlevel% EQU 1 goto :exit 
if %errorlevel% EQU 2 goto :Pre_Main

::
::End-Pos_Main
::

:exit
exit /b
此代码使用
tasklist
来计算
ffmpeg.exe
实例。如果计数更大 或等于输入的金额,脚本将 等待10秒钟,然后使用重试
任务列表
。这允许计算
ffmpeg.exe
实例的数量为 输入的金额

ffmpeg编码差异
  • 音频编码设置为
    -c:a libvorbis-b:a 64k
  • 第1遍的输出保存到
    nul
  • 插入
    -隐藏标题
    ,以减少控制台输出
  • -b:v 192
    更改为
    -b:v 192k
    ,因此比特率单位 类型已指定。似乎低比特率,也许应该 be
    -b:v 192K
  • 插入了
    -passlogfile
    参数,因此日志文件 要识别的已知且可能唯一的名称
  • 最后将删除第一个过程日志文件 第二关

虽然我建议转换为powershell。。。为什么现在要用
powershell
标记此文件?我看不出有什么时髦的东西。。。啊,对不起。。。我想我是在没有注意到的情况下加上去的。非常感谢。虽然与批处理文件相比,我在记忆和学习PowerShell脚本时遇到了一些问题,但我还是很想学习PowerShell脚本,所以到目前为止我一直坚持使用它。感谢您的修复![grin]如果你想学习PoSh,请在一个月的午餐时间内看看
学习Windows Powershell
。这本书是第三版,但它涵盖了到v3的所有高级思想,这是一个很大的变化。@LobaDK我建议您在尝试使其同时运行之前,首先封装该过程。为此,我认为应该将
For
循环放在它自己的文件中,并用参数调用它。看起来您需要一个输入和输出参数。在该批处理文件中,可以使用
%1
%2
引用这些批处理文件。然后,如果需要,这个顶级文件仍然可以提示输入变量,并在调用该变量时传递它们。顶层文件仍然可以做它需要做的事情,以生成子文件,但它将分离您的关注点并简化实现。Lee_Dailey感谢您的书籍推荐!有很多书要读,但我希望这不会让我感到厌烦@briantist也感谢您的推荐!若您可以用%1和%2显示一个示例,是否可能?我对使用这些东西还是有点陌生,很难理解我到底是怎么做的。谢谢你的剧本!我对它进行了一些修补,但是我似乎经常遇到问题,解决一个问题似乎只会导致另一个问题。很多时候,它似乎启动了正确数量的请求ffmpeg进程,但是FOR循环似乎不起作用,而是每个进程只转换一个视频。e、 g.如果我选择4个实例,那么它总共也只能转换4个视频。很多时候,无论出于什么原因,它似乎忽略了我给ffmpeg的一些参数,比如比特率。我也不确定
del
命令可以移动到其他地方。想想看。。。
批处理文件
本身不太可能改变ffmpeg可执行文件的参数(
比特率
)。“如果我选择4个实例,它也只转换4个视频”您的意思是如果运行4次
批处理
它转换4个视频,还是键入4作为它转换4个视频的数量?我不明白这部分,我看得不够清楚。对于
del
命令,在执行
start
命令后,父进程将继续。因此,在某个时候,可能会在其他“子”进程仍在运行时到达
del
命令。我不知道可能会删除其中一个临时文件
Echo "<FOR loop>"> command.bat
:next1
rem used to specify the input folder which the FOR loop should look in
set /p input=Input:

rem used to specify the output folder which the FOR loop should look in
set /p output=output:

rem used to specify how many time the GOTO loop should loop and start a new command prompt
set /p amount=:

if "%amount%"=="0" echo fatal error, please retry && goto :next1 

rem this creates a folder for the temporary files ffmpeg needs to store while doing the first pass in two-pass
mkdir "temp files"

@echo on

setlocal EnableDelayedExpansion

set loop=0
:loop
echo.
start cmd.exe for %%f in ("%input%\*.*") do ffmpeg -n -i "%%f" -c:v vp9 -c:a libopus -crf 20 -b:v 192 -pix_fmt yuv420p -pass 1 -f webm "temp files\!random!" && ffmpeg -n -i "%%f" -c:v vp9 -c:a libopus -crf 20 -b:v 192 -an -pix_fmt yuv420p -pass 2 %output%\%%~nf.webm
echo.
set /a loop=%loop%+1 
if "%loop%"=="%amount%" goto :next
if "%loop%"==11 goto :next
goto loop

:next
endlocal
del /q /f ffmpeg2pass*
del /q /f "temp files\*.*"

:end
choice /c EC /n /m "(E)xit or (C)ontinue"
if errorlevel 1 set exit=Quit
if errorlevel 2 set exit=Continue
if "%exit%"=="Quit" goto :exit
if "%exit%"=="Continue" goto :skip
:exit
exit
@echo off

setlocal EnableDelayedExpansion

:Pre_Main
::How many instances should be initiated. Limit hardcoded to 11.
::Input dir , Output dir.
set /p input=Input:
set /p output=Output:
set /p amount=Amount:

REM If not defined %amount% (
    REM echo Please specify a number of instances greater than 0
    REM goto :Pre_Main
REM )

if %amount% LEQ 0 (
    echo Please specify a number of instances greater than 0
    goto :Pre_Main
)

cd input

if exist ffmpeg_temp_files (
    rd /s /q ffmpeg_temp_files
) ELSE (
    md ffmpeg_temp_files
)

set "n_loop=1"

::
::End-Pre_Main
::

:loop
for %%f in (*) do (
    @echo on
    echo inside the loop... File: %%f n_loop: !n_loop!
    start "!n_loop!...%%f" ffmpeg.exe -n -i "%%f" -c:v vp9 -c:a libopus -crf 20 -b:v 192 -pix_fmt yuv420p -pass 1 -f webm "temp files\%%~nf_!time!_!n_loop!" && ffmpeg.exe -n -i "%%f" -c:v vp9 -c:a libopus -crf 20 -b:v 192 -an -pix_fmt yuv420p -pass 2 %output%\%%~nf.webm
    @echo off

    if !n_loop! GEQ !amount! goto :Pos_Main
    if !n_loop! EQU 12       goto :Pos_Main
    set /a n_loop=!n_loop!+1
)

:Pos_Main

endlocal

if exist ffmpeg_temp_files rd /s /q ffmpeg_temp_files
del /q /f ffmpeg2pass*

cd ..

choice /c EC /n /m "(E)xit or (C)ontinue"
if %errorlevel% EQU 1 goto :exit 
if %errorlevel% EQU 2 goto :Pre_Main

::
::End-Pos_Main
::

:exit
exit /b
@echo off
setlocal
set "tempdir=temp files"

:next1
rem Specify the input folder which the FOR loop should look in.
set /p "inputdir=InputDir: "
set "inputdir=%inputdir:"=%"

rem Specify the output folder which the FOR loop should look in.
set /p "outputdir=OutputDir: "
set "outputdir=%outputdir:"=%"

rem Specify how many time the GOTO loop should loop and start a new command prompt.
set "amount=0"
set /p "amount=Amount: "

rem Check if integer, else amount will be 0.
set /a "amount+=0"

rem Check if integer is 0.
if "%amount%" == "0" echo Please retry& goto :next1

rem Create a folder for the temporary files ffmpeg needs to store while doing the first pass in two-pass.
if not exist "%tempdir%" md "%tempdir%"

for %%A in ("%inputdir%\*.*") do call :encode "%%~A"
exit /b 0


:encode
setlocal
set "count=0"
set "imagename=ffmpeg.exe"

rem Run tasklist.
if %amount% gtr 1 (
    for /f %%A in ('tasklist /nh /fi "IMAGENAME eq %imagename%"') do (
        if /i "%%~A" == "%imagename%" set /a "count+=1"
    )
)

rem Check count of processes.
if %count% geq %amount% (
    >nul ping -n 10 localhost
    endlocal
    goto :encode
)

rem Set wait for 1 instance only.
set "wait="
if %amount% equ 1 set "wait=/w"

rem Encode with ffmpeg.
start "%ComSpec%" %wait%^
 cmd /c^
 ffmpeg -y -hide_banner -i "%~1" -c:v vp9 -crf 20 -b:v 192k -an -pix_fmt yuv420p -pass 1 -passlogfile "%tempdir%\%~n1" -f webm nul ^&^&^
 ffmpeg -y -hide_banner -i "%~1" -c:v vp9 -crf 20 -b:v 192k -c:a libvorbis -b:a 64k -pix_fmt yuv420p -pass 2 -passlogfile "%tempdir%\%~n1" "%outputdir%\%~n1.webm" ^&^&^
 del "%tempdir%\%~n1-0.log"
exit /b 0