如何将变量内可能包含特殊字符(例如 % 或 !)的命令传递给 for /f 循环?

How to pass a command that may contain special characters (such as % or !) inside a variable to a for /f loop?

我的代码中有一些嵌套循环,在某些时候,它们被这样的标签调用分开:

@echo off
chcp 65001
for /r %%a in (*.mkv *.mp4 *.avi *.mov) do (
    echo Processing "%%~a"
    call :innerloop "%%a" "%%~fa"
)
:: Instead of goto :eof, I chose cmd /k because I want the command prompt to still be open after the script is done, not sure if this is correct though
cmd /k

:innerloop
setlocal EnableExtensions EnableDelayedExpansion
for /f "delims=" %%l in ('mkvmerge.exe -i "%~1"') do (
:: Probably this would be a safer place for setlocal, but I believe that would mean that I wouldn't get to keep a single, different !propeditcmd! per processed file
    echo Processing line "%%~l"
    for /f "tokens=1,4 delims=: " %%t in ("%%l") do (
:: This section checks for mkv attachments. There are similar checks for chapters and global tags, all of those are handled by mkvpropedit.exe
        if /i "%%t" == "Attachment" (
            if not defined attachments (
                set /a "attachments=1"
            ) else (
                set /a "attachments+=1"
            )
            if not defined propeditcmd (
                set "propeditcmd= --delete-attachment !attachments!"
            ) else (
                set "propeditcmd=!propeditcmd! --delete-attachment !attachments!"
            )
        )
    )
)
:: Since !propeditcmd! (which contains the parameters to be used with the executable) is called after all lines are processed, I figured setlocal must be before the first loop in this label
if defined propeditcmd (
    mkvpropedit.exe "%~f1" !propeditcmd!
)
endlocal
goto :eof

该脚本适用于大多数文件,并像这样划分以允许在达到传递时打破内部循环而不破坏外部循环。虽然它适用于大多数文件,但我注意到它无法处理名称中包含括号 % 的文件名,这可能是由于 EnableDelayedExtensions.

通常,我知道我必须用插入符号 (^) 来转义这些字符,但如果特殊字符在变量中 ([=15],我不知道该如何做=]).

有办法吗?

更新: 我一直在努力将需要延迟扩展的部分与需要延迟扩展的部分分开,只需在我的代码末尾找到行 mkvpropedit.exe "%~f1" !propeditcmd!,由于 "%~f1"!propeditcmd!,它们都需要关闭和打开它。我认为这意味着没有办法解决这个问题,转义是必要的。

继续我的研究, seem to suggest this could be achieved with something like set filename="%~1:!=^^!". Nevertheless, this doesn't seem to be the proper syntax according to SS64。我也不确定这是否会用 ^! 替换所有出现的 ! 并且我还担心这种替换会创建一个无限循环如果它不会更适合执行此操作首先将 ! 替换为 ¬,然后再将其替换为 ^!.

虽然我打算尽快进行测试以确定所有这些,但我担心我可能无法涵盖所有​​内容,因此我们将不胜感激。


PS:完整代码(88 行)可用 here 如果需要更多上下文,尽管我会根据要求编辑此问题中的代码段!

编辑: 一开始我认为它不相关,但现在我认为了解什么是 mkvmerge.exe -i 的标准输出会有所帮助:

File 'test.mkv': container: Matroska
Track ID 0: video (AVC/H.264/MPEG-4p10)
Track ID 1: audio (Opus)
Track ID 2: subtitles (SubRip/SRT)
Attachment ID 1: type 'image/jpeg', size 30184 bytes, file name 'test.jpg'
Attachment ID 2: type 'image/jpeg', size 30184 bytes, file name 'test2.jpg'
Attachment ID 3: type 'image/jpeg', size 30184 bytes, file name 'test3.jpg'
Chapters: 5 entries
Global tags: 3 entries

真的不需要子程序。最后需要延迟变量扩展,但可以先将完全限定的文件名分配给环境变量,如 FileName 以避免文件名包含感叹号的麻烦。

根据问题贴出的代码重写的代码,加上一些注释:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "WindowTitle=%~n0"

rem Find out if the batch file was started with a double click which means
rem with starting cmd.exe with option /C and the batch file name appended
rem as argument. In this case start one more Windows command processor
rem with the option /K and the batch file name to keep the Windows command
rem processor running after finishing the processing of this batch file
rem and exit the current command processor processing this batch file.
rem This code does nothing if the batch file is executed from within a
rem command prompt window or it was restarted with the two options /D /K.

setlocal EnableDelayedExpansion
for /F "tokens=1,2" %%G in ("!CMDCMDLINE!") do (
    if /I "%%~nG" == "cmd" if /I "%%~H" == "/c" (
        endlocal
        start %SystemRoot%\System32\cmd.exe /D /K %0
        if not errorlevel 1 exit /B
        setlocal EnableDelayedExpansion
    )
)

rem Set the console window title to the batch file name.
title !WindowTitle!
endlocal
set "WindowTitle="

rem Get the number of the current code page and change the code page
rem to 65001 (UTF-8). The initial code page is restored at end.
for /F "tokens=*" %%G in ('%SystemRoot%\System32\chcp.com') do for %%H in (%%G) do set "CodePage=%%~nH"
%SystemRoot%\System32\chcp.com 65001 >nul 2>&1

for /R %%G in (*.mkv *.mp4 *.avi *.mov) do (
    echo(
    echo Processing "%%~G"
    set "Attachments="
    for /F "delims=" %%L in ('mkvmerge.exe -i "%%G"') do (
        rem echo Processing line "%%L"
        for /F "delims=: " %%I in ("%%L") do if /I "%%I" == "Attachment" set /A Attachments+=1
    )
    if defined Attachments (
        set "FileName=%%G"
        setlocal EnableDelayedExpansion
        set "propeditcmd=--delete-attachment 1"
        for /L %%I in (2,1,!Attachments!) do set "propeditcmd=!propeditcmd! --delete-attachment %%I"
        mkvpropedit.exe "!FileName!" !propeditcmd!
        endlocal
    )
)

rem Restore the initial code page.
%SystemRoot%\System32\chcp.com %CodePage% >nul
endlocal

为什么 window 标题通过延迟扩展传递给 TITLE?

如果在扩展动态变量、环境变量、循环变量或批处理文件参数引用space 或这些字符之一 &()[]{}^=;!'+,`~<>| 如果所有这些字符都应由 Windows 命令处理器 cmd.exe 按字面解释。出于这个原因,第三行用双引号将参数字符串 WindowTitle=%~n0 括起来,因为 %~n0 引用没有文件扩展名且没有路径的批处理文件名,例如,可能包含一个和号,尽管那将是一个批处理文件的常用文件名。

另请参阅:How does the Windows Command Interpreter (CMD.EXE) parse scripts?

命令 TITLE 就像关于 " 的命令 ECHO。它始终将双引号解释为文字字符,并且不会将它们从参数字符串中删除。因此,使用 title "%WindowTitle%" 会导致控制台的标题 window 以双引号开头和结尾。那看起来不太好。因此,作为 window 标题的批处理文件名称应该传递给 cmd.exe 内部命令 TITLE,而不用双引号。但如果批处理文件名包含一个字符,该字符对 cmd.exe 在执行命令 TITLE 之前处理命令行具有特殊含义,例如 &。因此,延迟变量扩展被启用并在此处用于引用分配给环境变量 WindowTitle 的批处理文件名,这使得根据批处理文件名真正设置的 window 标题成为可能。

为什么最后确定并恢复当前代码页?

一个好的批处理文件供很多人使用,在执行环境上改变一些东西应该总是恢复初始执行环境,除非批处理文件明确设计用于定义批处理文件执行完成后执行的应用程序和脚本的执行环境.

这对批处理文件开发意味着什么?

与启动批处理文件时的 属性 值相比,完成批处理文件的执行后,执行环境的以下属性应保持不变:

  1. 环境变量列表及其值;
  2. 命令扩展的状态;
  3. 延期扩容状态;
  4. 当前目录;
  5. 命令提示符;
  6. 文本和背景颜色;
  7. 用于字符编码的代码页;
  8. 控制台的行数和列数window.

执行环境的前四个属性在使用批处理文件 SETLOCAL 和底部 ENDLOCAL 时未被修改.批处理文件底部的显式 ENDLOCAL 是可选的,因为 cmd.exe 调用它对于每个 SETLOCAL 没有执行匹配 ENDLOCAL 退出批处理文件处理之前独立于退出批处理文件处理的原因。

另请参阅:How to pass environment variables as parameters by reference to another batch file?
它详细解释了每次执行 SETLOCALENDLOCAL.

时发生的情况

对于每个成功执行的 PUSHD 还应该执行 POPD 以恢复初始当前目录。

只有在使用命令 PROMPT 更改命令提示符时才需要恢复命令提示符,而大多数批处理文件根本不会这样做。

使用 CHCP 更改代码页应该导致在批处理文件末尾再次使用 CHCP 来恢复原始代码页。使用命令 COLOR 更改文本颜色和背景颜色,使用命令 MODE 更改行和列控制台 window.

请参阅 DosTips 论坛主题 [Info] Saving current codepage, especially the post written by Compo,了解有关将当前代码页编号分配给环境变量的说明,该环境变量在批处理文件末尾用于恢复初始代码页。

有点难以理解为什么获取当前代码页号是通过两个 FOR 循环完成的,其中第二个循环使用修饰符 %~n 虽然输出of chcp.com 绝对不是文件名。那么让我们看看德国人 Windows 上发生了什么,命令 CHC 输出字符串:

Aktive Codepage: 850.

不需要输出末尾的点,只需要像英语 Windows 那样的代码页码,输出为:

Active code page: 850

根据 Windows 的语言,请参阅参考的 DosTips 主题了解其他变体。

chcp.com 的输出首先完全分配给循环变量 G,如果 chcp.com 将输出代码页,则删除前导正常 spaces 和水平制表符前导 spaces/tabs 的信息。第二个 FOR 循环使用正常的 space、逗号、分号、等号和 OEM 编码的 no-break space 作为单词分隔符来处理这个单词列表.

第二个 FOR 循环运行命令 SET 三遍以获得德语代码页信息,字符串为:

  1. Aktive
  2. Codepage:
  3. 850.

修饰符 %~n 的使用现在导致 3 次通过 cmd.exe 访问文件系统并在当前目录中搜索具有分配给循环变量 [=38= 的字符串的文件] 作为文件名。很可能没有文件 Aktive。末尾有冒号的 Codepage: 是一个无效的文件名,并且很可能在 Windows 文件 IO API 函数中也找不到带有尾随点的文件 850当前目录。但是,文件系统条目是否偶然匹配这三个字符串之一并不重要,因为 %~n 导致仅使用从开头到最后一个点之前的字符的字符串。所以命令 SET 第一次用 Aktive 执行,第二次用 Codepage: 执行,最后第三次用 850 执行。所以环境变量 CodePage 最后只用数字 850.

定义

处理视频文件的主要 FOR 循环说明

最外层的FOR将找到的文件名总是全路径不包围"赋值给指定的循环变量G因为使用选项 /R。因此,在必须引用完全限定文件名以加速文件名处理的地方,只使用 "%%G" 而不是 "%%~G"

echo(输出空行,见DosTips论坛主题ECHO. FAILS to give text or blank line - Instead use ECHO/

如果在 SET 计算的算术表达式中引用了未定义的环境变量,如 Attachments,则使用值 0,如用法所解释命令提示符 window 中 运行 set /? 的帮助输出。因此,set /A Attachments+=1 可用于在第一次执行时用 1 定义变量,或者在当前文件的所有进一步执行中将环境变量 Attachments 的值增加一个。

环境变量 Attachments 的最终值是在处理完 mkvmerge 输出的所有行后求得的。如果有附件,文件名将分配给环境变量 FileName,并且仍然禁用延迟变量扩展,因此 ! 被解释为文字字符。接下来根据附件数量动态创建环境变量propeditcmd

整个视频文件处理任务的优化代码

我既没有安装 mkvmerge.exe 也没有安装 mkvpropedit,但我也查看了引用的完整代码。这是您完整代码的重写优化版本,没有任何评论,我无法真正完全测试。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "WindowTitle=%~n0"
setlocal EnableDelayedExpansion
for /F "tokens=1,2" %%G in ("!CMDCMDLINE!") do (
    if /I "%%~nG" == "cmd" if /I "%%~H" == "/c" (
        endlocal
        start %SystemRoot%\System32\cmd.exe /D /K %0
        if not errorlevel 1 exit /B
        setlocal EnableDelayedExpansion
    )
)
title !WindowTitle!
endlocal

for /F delims^=^=^ eol^= %%G in ('set ^| %SystemRoot%\System32\findstr.exe /B /I /L /V "ComSpec= PATH= PATHEXT= SystemRoot= TEMP= TMP="') do set "%%G="

if exist "%~dp0mkvmerge.exe" (set "ToolsPath=%~dp0") else if exist mkvmerge.exe (set "ToolsPath=%CD%") else for %%I in (mkvmerge.exe) do set "ToolsPath=%%~dp$PATH:I"
if not defined ToolsPath echo ERROR: Could not find mkvmerge.exe!& exit /B 2
if "%ToolsPath:~-1%" == "\" set "ToolsPath=%ToolsPath:~0,-1%"
if not exist "%ToolsPath%\mkvpropedit.exe" echo ERROR: Could not find mkvpropedit.exe!& exit /B 2

for /F "tokens=*" %%G in ('%SystemRoot%\System32\chcp.com') do for %%H in (%%G) do set /A "CodePage=%%H" 2>nul
%SystemRoot%\System32\chcp.com 65001 >nul 2>&1

del /A /F /Q Errors.txt ExtraTracksList.txt 2>nul

(
set "ToolsPath="
set "CodePage="

for /F "delims=" %%G in ('dir *.mkv /A-D-H /B /S 2^>nul') do (
    echo --^> Processing file "%%G" ...
    setlocal
    set "FullFileName=%%G"
    for /F "tokens=1,4 delims=: " %%H in ('^""%ToolsPath%\mkvmerge.exe" -i "%%G" --ui-language en^"') do (
        if /I "%%I" == "audio" (
            set /A AudioTracks+=1
            setlocal EnableDelayedExpansion
            if !AudioTracks! == 2 echo !FullFileName!>>ExtraTracksList.txt
            endlocal
        ) else if not defined SkipFile if /I "%%I" == "subtitles" (
            echo --^> "%%~nxG" has subtitles
            "%ToolsPath%\mkvmerge.exe" -o "%%~dpnG.nosubs%%~xG" -S -M -T -B --no-global-tags --no-chapters --ui-language en "%%G"
            if not errorlevel 1 (
                echo --^> Deleting old file ...
                del /F "%%G"
                echo --^> Renaming new file ...
                ren "%%~dpnG.nosubs%%~xG" "%%~nxG"
            ) else (
                echo Warnings/errors generated during remuxing, original file not deleted, check Errors.txt
                "%ToolsPath%\mkvmerge.exe" -i --ui-language en "%%G">>Errors.txt
                del "%%~dpnG.nosubs%%~xG" 2>nul
            )
            set "SkipFile=1"
        ) else if /I "%%H" == "Attachment"  (
            set /A Attachments+=1
        ) else if /I "%%H" == "Global" (
            set "TagsAll=--tags all:"
        ) else if /I "%%H" == "Chapters" (
            set "Chapters=--chapters """
        )
    )
    if not defined SkipFile (
        set "OnlyFileName=%%~nxG"
        setlocal EnableDelayedExpansion
        if defined Attachments (
            set "PropEditOptions= --delete-attachment 1"
            for /L %%H in (2,1,!Attachments!) do set "PropEditOptions=!PropEditOptions! --delete-attachment %%H"
        )
        if defined TagsAll set "PropEditOptions=!PropEditOptions! !TagsAll!"
        if defined Chapters set "PropEditOptions=!PropEditOptions! !Chapters!"
        if defined PropEditOptions (
            echo --^> "!OnlyFileName!" has extras ...
            "%ToolsPath%\mkvpropedit.exe" "!FullFileName!"!PropEditOptions!
        )
        endlocal
    )
    echo(
    echo ##########
    echo(
    endlocal
)
for /F "delims=" %%G in ('dir *.avi *.mp4 *.mov /A-D-H /B /S 2^>nul') do (
    echo Processing file "%%G" ...
    "%ToolsPath%\mkvmerge.exe" -o "%%~dpnG.mkv" -S -M -T -B --no-global-tags --no-chapters --ui-language en "%%G"
    if not errorlevel 1 (
        echo --^> Deleting old file ...
        del /F "%%G"
    ) else (
        echo --^> Warnings/errors generated during remuxing, original file not deleted.
        "%ToolsPath%\mkvmerge.exe" -i --ui-language en "%%G">>Errors.txt
        del "%%~dpnG.mkv" 2>nul
    )
    echo(
    echo ##########
    echo(
)

if exist Errors.txt for %%G in (Errors.txt) do if %%~zG == 0 del Errors.txt 2>nul
%SystemRoot%\System32\chcp.com %CodePage% >nul
)
endlocal

移除本地环境中不需要的环境变量

批处理文件必须使用多个环境变量处理可能数百甚至数千个文件。

每个 MKV 文件至少使用一次 SETLOCALENDLOCAL 创建当前环境变量列表的副本,完成后丢弃当前 MKV 文件的处理。

还为每个视频文件执行了其他程序,Windows 内核库函数CreateProcess 还创建了当前进程的当前环境变量列表的副本。

因此,使用本地环境变量列表很有帮助,该列表仅包含处理视频文件期间真正需要的环境变量。

设置 window 标题后的第一个 FOR 在后台运行 cmd.exe 如下:

C:\Windows\System32\cmd.exe /c set | C:\Windows\System32\findstr.exe /B /I /L /V "ComSpec= PATH= PATHEXT= SystemRoot= TEMP= TMP="

启动cmd.exeset在后台输出相同的环境变量列表及其值作为处理批处理文件的命令进程当前使用的值。这些行被传递给 findstr,后者搜索 case-insensitive (/I) 并按字面意义 (/L) 在每行的开头搜索 space 分隔的字符串 (/B) 并输出反转结果 (/V),这意味着所有行 NOT 以 space 分隔字符串之一开头。因此,输出所有环境变量,并从它们的 va 中用 = 分隔ues,除了 findstr.

搜索和找到的那些

捕获的行由 FOR 处理,使用等号作为字符串分隔符,没有字符作为行尾字符来处理甚至名称以 a 开头的环境变量分号并分配给循环变量 G 只是用于从当前环境变量列表中删除变量的变量名称。

所以只剩下环境变量ComSpecPATHPATHEXTSystemRootTEMPTMP

使用完全限定的文件名以避免不必要的文件系统访问

大多数人在批处理文件中只使用 executables 的文件名,没有文件扩展名和文件路径,这会强制 cmd.exe 在当前目录和下一个目录中指定的所有目录中搜索文件的环境变量 PATH,文件扩展名在环境变量 PATHEXT 中指定。这导致在每个文件上调用 executables 的循环中处理数百个文件时进行数千次文件系统访问。

所有这些文件系统访问都可以通过在批处理文件中指定每个 executable 及其完全限定的文件名来避免。这并不意味着批处理文件必须已经包含每个 executable 的完全限定文件名,如上面的代码所示,因为 executable 的完整文件名也可以在批处理文件的开头。

批处理文件首先检查 mkvmerge.exe 是否在批处理文件的目录中,如果文件检查是肯定的,则使用完整的批处理文件路径定义环境变量 ToolsPath。否则在当前目录中搜索 executable mkvmerge.exe 并且当前目录路径分配给 ToolsPath 如果有文件系统条目(希望是文件而不是目录)名字 mkvmerge.exe。最后在环境变量PATH的目录中搜索mkvmerge.exe,如果找到则将此目录路径分配给ToolsPath.

批处理文件输出错误信息,恢复初始环境并在executable上退出mkvmerge.exe或另一个mkvpropedit.exe根本找不到

%~dp0%%~dp$PATH:I 扩展为始终以反斜杠结尾的路径字符串。 %CD% 扩展为不以反斜杠结尾的路径字符串,但当前目录是驱动器的根目录。因此,使用带有字符串比较的 IF 条件来检查分配给 ToolsPath 的路径字符串是否以反斜杠结尾,在这种情况下,使用此反斜杠重新定义环境变量删除。在下面的代码中引用 ToolsPath.

的路径字符串时添加了反斜杠

使用不同的方法确定当前代码页

这次使用Compo开发的第一个方案来判断当前代码页的编号。它类似于使用相同的两个 FOR 循环的其他解决方案,但是第二个 FOR[ 执行的命令 SET =392=] 循环现在评估一个算术表达式,以在最后一次迭代中获取没有分配给环境变量的点的代码页编号 CodePage.

让我们再看看处理字符串时发生了什么:Aktive Codepage: 850.

首先执行了set /A "CodePage=Aktive"导致环境变量CodePage被定义为值0因为Aktive被解释为环境变量名称并且没有这样的环境变量。接下来执行 set /A "CodePage=Codepage:" 具有相同的解释和相同的结果 0。最后执行 set /A "CodePage=850." 导致错误消息 Missing operator. to handle STDERR redirected to the device NUL to suppress它。但是,分配给环境变量 CodePage 的值是 850 想要的。

此解决方案的优点是在算术表达式中使用 %%H,不会导致任何文件系统访问。所以我认为这个解决方案总体上更好。

如何在处理视频文件时避免批处理文件访问?

推荐阅读Why is a GOTO loop much slower than a FOR loop and depends additionally on power supply?

结论:将处理数百或数千个文件所需的全部代码放入一个命令块中是一个好主意,Windows 命令处理器只读取和解析一次。

在大多数情况下,问题是如何处理变量值在命令块中发生变化,而不使用所有时间延迟扩展,因为这会影响对文件名等字符串的处理。这在大多数情况下并不容易,但通常是可能的,如上面的代码所示。

环境变量 ToolsPathCodePage 可以在主代码块的开头立即取消定义,因为命令处理器已经将所有 %ToolsPath%%CodePage% 替换为执行前的适当路径和代码页码字符串执行第一个命令 set "ToolsPath="。因此,第一个主 FOR 循环执行时的当前环境变量列表仅包含 findstr.

找到的五个环境变量

Windows 命令处理器在完成所有视频文件的处理并恢复原始代码页之前不再访问批处理文件。

关于第二批文件中代码的其他特殊信息

如果文件系统不阻止删除文件,则总是先使用命令 DEL 删除包含处理视频文件过程中收集的信息的两个文本文件。

使用了两次 for /F 而不是 for /R 作为主要 FOR 循环首先获取要处理的视频文件的所有文件名,并加载完整路径进入 Windows 命令处理器的内存,然后处理视频文件,而不是像 for /R 那样遍历当前文件系统条目。这对于循环处理 *.mkv 文件有很大的不同,特别是在存储在 FAT32 或 exFAT 格式驱动器上的视频文件上,文件分配 table 不仅在处理 MKV 文件时发生变化,而且在 NTFS 格式的驱动器上,但不会像在 NTFS 格式的驱动器上那样以本地字母排序在文件分配 table 中更新。 for /R 的使用可能会导致 FAT32 或 exFAT 格式的驱动器多次处理 MKV 文件或跳过意外的一个或多个 MKV 文件,这是由于执行 table 引起的文件分配更改mkvmergemkvpropedit 在 MKV 文件上。

命令SETLOCALENDLOCAL 用于快速恢复始终在主[=317= 之外定义的最小环境变量列表]FOR 对每个 MKV 文件进行循环,这导致在处理 MKV 文件时始终丢弃对环境变量列表所做的所有更改。

mkvmerge.exe 的执行及其带有选项 -i 的完整路径和当前 MKV 文件的全名再 cmd.exe/c 开始并指定考虑到 %ToolsPath%%%G 也可能包含 & 之类的字符,要通过 cmd.exe 处理批处理文件将其解释为文字字符,命令行有点棘手,而且由 cmd.exe 在后台启动。

需要用双引号将 cmd.exe 在后台执行的整个命令行括起来,以便此 cmd.exe 实例正确处理。但是处理批处理文件的 cmd.exe 实例必须将这两个 " 解释为文字字符,而不是参数字符串的开头或结尾。否则,开头的 "" 将被 cmd.exe 解释为将批处理文件处理为空参数字符串的开头和结尾。因此,对于 cmd.exe 处理批处理文件,工具路径字符串将不再用双引号引起来,这在包含 &').[= 时当然是有问题的181=]

出于这个原因,在 " 中将整个命令行括起来的两个双引号在批处理文件中指定,并使用脱字符 ^ 进行转义,从而导致 cmd.exe处理批处理文件会将这两个双引号解释为文字字符,而不是参数字符串的 beginning/end。

结果是 "%ToolsPath%\mkvmerge.exe""%%G" 都被 cmd.exe 解释为双引号参数字符串,因此可以包含所有解释为文字字符的字符,否则这些字符将被解释为有特殊意义。

有关音轨的信息始终独立于以何种顺序处理 mkvmerge.exe 输出有关当前 MKV 文件的信息数据。但是一旦定义了环境变量SkipFile,所有其他信息都不会进一步处理,因为当前MKV文件有字幕。

文件 Errors.txt 在创建时被删除,但最终大小为 0 字节。

使用的 Windows 命令的使用帮助

为了了解使用的命令及其工作原理,请打开 command prompt window,在那里执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • call /?
  • chcp /?
  • cmd /?
  • dir /?
  • del /?
  • echo /?
  • endlocal /?
  • exit /?
  • findstr /?
  • for /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?
  • start /?
  • title /?

另请参阅 Issue 7: Usage of letters ADFNPSTXZadfnpstxz as loop variable 以及其他有关初学者在批处理文件编码中提出的一般问题的章节。