文件夹内的批处理文件以创建 MediaInfo.nfo 文件
Posted
技术标签:
【中文标题】文件夹内的批处理文件以创建 MediaInfo.nfo 文件【英文标题】:Batch files inside folder to create MediaInfo.nfo file 【发布时间】:2021-05-17 07:43:47 【问题描述】:我正在尝试创建一个批处理,其目的是使用 MediaInfo.exe (CLI) 创建单个文本文件 (.nfo),其中包含文件夹中包含的视频文件的所有“媒体信息”。
批处理从上下文菜单执行:右键单击包含视频文件的文件夹。 为此,该文件将被放置在“shell:sendto”中。
生成的包含所有媒体信息的 .nfo 文件必须“放置/保存或移动”在包含视频文件的文件夹中。
一个特殊之处是我需要更改最终的 .nfo 文件,以便删除“完整名称”行的所有路径部分:
Complete name : /Users/me/Downloads/Folder1/Folder2/RÉCENTS/[File] File Name - 185 (Encode Format 1080p).mkv
在此示例中:进行搜索和替换以仅离开:
Complete name : [File] File Name - 185 (Encode Format 1080p).mkv
目前,我已经成功创建了这个批次(链接如下)。 这个有一些错误,即:
找不到文件 (x2) 如果有特殊字符,Powershell 会出错总结Batch搜索的过程:
1.右键单击包含文件的文件夹>发送到>单击批处理文件。
2.创建文件夹中包含的文件的所有Media info txt文件
3. 通过在每个内容之间添加分隔符“----”来合并 Media Info txt 文件。
4. 使用正则表达式在最终文件上搜索和替换以删除文件名之前的所有路径,然后将 (.nfo) 保存在文件夹中。
5.清除步骤 2 中的旧临时文件。
The actual Batch files I managed to create:
@echo off
:: Fullpath current folder : %cd%
:: Fullpath folder where the right click was made : %~f1
:: Name of the folder where the right click was made : for %%f in ("%~f1") do set Name=%%~nxf
for %%f in ("%~f1") do set Name=%%~nxf
:: Step 1: Creating a temporary folder
mkdir "%~f1-Temp"
:: Step 2: Creation of all nfo txt files in the temporary folder
FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (
call "C:\Users\me\Desktop\MediaInfo\MediaInfo.exe" "%~f1\%%G" > "%~f1-Temp\%%~nG.txt"
)
:: Step 3: Filling in the final nfo
setlocal enabledelayedexpansion
set i=0
FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (
IF !i! == 1 (
echo ------------------------------------------------------------------------------------------------------------------------------------ >> "%~f1-Temp\%Name%.txt"
echo. >> "%~f1-Temp\%Name%.txt"
echo. >> "%~f1-Temp\%Name%.txt"
)
cat "%~f1-Temp\%%~nG.txt" >> "%~f1-Temp\%Name%.txt"
set i=1
)
endlocal
:: Step 4: Removing the path
setlocal
set $source="%~f1-Temp\%Name%.txt"
set $dest="%~f1-Temp\%Name%1.txt"
set "search=%~f1\\"
for /f "delims=" %%a in ('powershell -c "(get-content '%$source%') | foreach-object $_ -replace '(?<=Complete name\s+:\s+).+\\' | set-content '%$dest%'"') do echo %%a
endlocal
:: Step 5: Renaming the nfo and moving to the right place
Ren "%~f1-Temp\%Name%1.txt" "%Name%.nfo"
move "%~f1-Temp\%Name%.nfo" "%~f1"
:: Step 6: Deleting temporary files
rmdir /s /q "%~f1-Temp"
pause
如果您对已编码的内容有改进或/和更正的建议,请不要犹豫! 提前感谢您的帮助!
【问题讨论】:
【参考方案1】:我认为您自己创建了一个问题,方法是向 MediaInfo 提供完整路径作为参数。如果您只提供文件名,Complete name
将只反映文件名。
此外,除非我误解了您的意图,否则当我不认为有必要时,您会跳过很多圈。
以下示例批处理文件应该在您常用的脚本目录中创建,如果您愿意,甚至可以在“文档”中创建。
然后你应该在你的“SendTo”目录中创建一个快捷方式,给它一个你能理解的名字,也许是MediaNFO
。
现在您需要做的就是右键单击您的目录并选择Send to
➡ MediaNFO
。这应该在右键单击的目录中创建一个与该目录同名的文件,并包含它包含的每个受支持文件的mediainfo
输出。 Complete name
行不应包含路径信息,只应包含 File name
。
@Echo Off
SetLocal EnableExtensions
Set "MIExe=%UserProfile%\Standalone\MediaInfo\MediaInfo.exe"
Set "OutExt=nfo"
Set "HR=------------------------------------------------------------------"
For %%G In ("%~1") Do If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error! File arg.
GoTo EndIt) Else (Echo Error! Invalid directory arg.
GoTo EndIt)) Else If "%%~dG" == "" (
Echo Error! Full directory path required.
GoTo EndIt)
If Not Exist "%MIExe%" (Echo Error! MediaInfo not found.
GoTo EndIt)
PushD "%~1"
Set "ExtLst="
For %%G In (aac ac3 aifc aiff ape asf au avi avr dat dts flac iff ifo irca m1v
m2v mac mat mka mks mkv mov mp2 mp3 mp4 mpeg mpg mpgv mpv ogg ogm paf pvf qt
ra rm rmvb sd2 sds vob w64 wav wma wmv xi) Do If Not Defined ExtLst (
Set "ExtLst=".":"*.%%G"") Else Call Set "ExtLst=%%ExtLst%% ".":"*.%%G""
Set "=%PATHEXT%" && Set "PATHEXT="
%SystemRoot%\System32\where.exe /Q %ExtLst%
If ErrorLevel 1 (Echo Error! Directory has no supported files.
GoTo EndIt)
Set "i="
(For /F "Delims=" %%G In ('%SystemRoot%\System32\where.exe %ExtLst% 2^> NUL'
) Do (If Defined i Echo %HR%
"%MIExe%" "%%~nxG"
Set "i=T")) 1> "%~nx1.%OutExt%"
:EndIt
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
GoTo :EOF
您可以在4
上更改mediainfo.exe
的位置,并在5
上更改输出扩展名;但不应修改其他任何内容。
您还应该注意,我已在此脚本中添加了一些输入验证。如果您的输入目录不是包含现有 mediainfo 可执行文件的支持文件的完全限定目录路径,它将报告错误并关闭。
【讨论】:
您好@Compo,感谢它完美运行。另一方面,如果可以将它们添加到 InExt 检查中,我不仅有 .mkv 文件,还有任何类型的视频文件(.avi.mp4.mkv,...)? 我还想添加直接在文件上进行批处理的可能性(.nfo 保存在与视频文件相同的位置),现在它保存在批处理位置。 我已经替换了上面答案中的代码,以适应 mediainfo 支持的所有文件类型,快速查看here。 @use2276368,尽管您没有在问题中提到该要求。但是,您指定您正在右键单击文件夹,并且您提供的代码正在使用文件夹输入。绝对没有提到右键单击文件,所以不幸的是,这是一个不同的任务和新问题。但是,根据您的两个答案中提供的技术和建议,您应该尝试自己编写代码。 你好@Compo,非常感谢!我也会检查是否为单个文件调整它。我希望能到达那里! 我提出了一个新问题,因为我不明白如何在没有单个文件之前的路径的情况下创建 nfo 文件..:The Question【参考方案2】:1。 Windows CMD 与 PowerShell
Windows 命令处理器 (cmd.exe
) 正在处理一个批处理文件。它的继任者是功能更强大的脚本解释器 PowerShell (powershell.exe
)。在批处理文件中使用 PowerShell 并没有真正意义,因为在这种情况下,最好使用 PowerShell 语法使用 PowerShell 脚本来完成整个任务。为此,我编写了一个纯 Windows 命令处理器解决方案。
2。文件/文件夹名称未用双引号括起来
应始终引用包含在"
中的文件/文件夹名称,否则批处理文件可能无法处理包含空格或其中一个字符&()[]^=;!'+,`~
的文件/文件夹名称。大多数引用文件或文件夹名称的参数字符串在相关代码中用双引号括起来,但有些不是。
见:Syntax error in one of two almost-identical batch scripts: “)” cannot be processed syntactically here
3。命令DIR的错误使用
第一个 FOR 循环没有正常工作:
FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (
命令 DIR 由另一个在后台启动的命令进程执行,该命令进程使用%ComSpec% /c
和'
中的命令行作为附加参数附加到裸格式输出(只是文件/文件夹名称没有路径)在批处理文件执行时在当前目录中使用%~f1
指定的目录中的所有文件/文件夹以及与模式*.mkv
匹配的所有文件/文件夹。这是不正确的。正确的做法是 dir "%~f1\*.mkv" /A-D /B
仅输出 %~f1
引用的目录中所有文件扩展名为 .mkv
的文件的名称。
这两个文件未找到错误消息最有可能是因为在当前目录中找不到*.mkv
文件/文件夹,无论执行批处理文件时的当前目录是什么。
文件名由 DIR 输出,不带路径,但选项 /S
用于递归搜索。在处理 DIR 输出的文件名时必须考虑到这一点,这不是在问题中发布的批处理代码中完成的。
4。启用延迟扩展不利于使用 FOR 循环处理文件名
在 FOR 循环上启用 delayed expansion 处理文件名、文本文件中的行或从后台执行的命令进程的标准输出中捕获的行并不好,因为它会导致在执行前第二次解析 FOR 为每个文件名执行的命令块内的命令行。在这种情况下,无法正确处理包含一个或多个感叹号的文件/文件夹名称或行,因为 !
在第二次解析时被 cmd.exe
解释为延迟扩展环境变量引用的开始/结束,而不是文字字符文件名或行。
见:How does the Windows Command Interpreter (CMD.EXE) parse scripts?
5。 cat 不是 Windows 命令
cat
不是Windows command。这是一个从 Unix/Linux 移植到 Windows 或在 Windows 10 上使用 Subsystem for Linux (WSL) 执行的工具。
因此,最好避免使用 cat
,因为 Windows 默认情况下不可用,具体取决于 Windows 版本和用户配置。
6。命令 CALL 对运行可执行文件没有用
CALL 命令对于从批处理文件中运行可执行文件没有用。在处理批处理文件中的下一个命令行之前,运行可执行文件并等待自终止是 Windows 命令处理器的默认行为。
CALL命令主要用于从批处理文件中调用批处理文件。
在命令行上使用命令 CALL 只是运行一个可执行文件,这会使批处理文件的处理速度变慢,因为在这种情况下,cmd.exe
进程在这种情况下第二次使用命令行类似于用法执行命令行前的延迟扩展。
7。用于在一个 .nfo 文件中收集视频信息的批处理文件
我没有安装 MediaInfo 工具,也没有 MKV 文件或其他视频文件。将传递给批处理文件的路径的目录设为当前目录并运行MediaInfo.exe
与该目录中的视频文件的名称可能就足够了,以获取Complete name
信息写入没有路径的文件中。 MediaInfo 似乎也是从 Unix/Linux 移植的工具,因为它输出的视频文件的完整名称没有驱动器号和冒号,并且使用 /
而不是 \
。反斜杠是 Windows 上的目录分隔符,因为它可以在有关 Naming Files, Paths, and Namespaces 的 Microsoft 文档中阅读。
不使用 PowerShell 或 cat
的批处理文件代码:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "MediaInfoTool=%UserProfile%\Desktop\MediaInfo\MediaInfo.exe"
rem Assign the folder path passed to batch file to environment variable FolderPath.
set "FolderPath=%~1"
rem Use the batch file path if started without a folder path argument.
if not defined FolderPath set "FolderPath=%~dp0"
rem Remove all double quotes from folder path.
set "FolderPath=%FolderPath:"=%"
if not defined FolderPath set "FolderPath=%~dp0"
rem Replace all slashes by backslashes in folder path.
set "FolderPath=%FolderPath:/=\%"
rem Make sure the folder path ends with a backslash.
if not "%FolderPath:~-1%" == "\" set "FolderPath=%FolderPath%\"
rem Check existence of folder and output an error message if not existing.
if not exist "%FolderPath%" echo ERROR: Could not find folder: "%FolderPath%"& goto EndBatch
rem Check existence of any video file in folder and output an error message if not existing.
if not exist "%FolderPath%*.avi" if not exist "%FolderPath%*.mp4" if not exist "%FolderPath%*.mpg" if not exist "%FolderPath%*.mkv" echo ERROR: There is no *.avi or *.mp4 or *.mpg or *.mkv file in folder: "%FolderPath%"& goto EndBatch
rem Check existence of MediaInfo executable and output an error message if not existing.
if not exist "%MediaInfoTool%" echo ERROR: Could not find file: "%MediaInfoTool%"& goto EndBatch
rem Get just the folder name without path and full qualified folder name.
for %%I in ("%FolderPath%.") do set "FolderName=%%~nxI" & set "FolderPath=%%~fI"
rem Make sure the following environment variable is not defined.
set "Separator="
(for /F "eol=| delims=" %%I in ('dir "%FolderPath%\*.avi" "%FolderPath%\*.mpg" "%FolderPath%\*.mp4" "%FolderPath%\*.mkv" /A-D /B') do (
if defined Separator (
echo ------------------------------------------------------------------------------------------------------------------------------------
echo(
echo(
)
set "Separator=1"
set "OutputLine="
for /F "delims=" %%J in ('^""%MediaInfoTool%" "%FolderPath%\%%I" ^| %SystemRoot%\System32\findstr.exe /N /R "^"^"') do (
set "InfoLine=%%J"
setlocal EnableDelayedExpansion
if defined OutputLine (
echo(!InfoLine:*:=!
endlocal
) else if "!InfoLine::Complete name=!" == "!InfoLine!" (
echo(!InfoLine:*:=!
endlocal
) else (
for /F "tokens=1* delims=/" %%K in ("!InfoLine:*:=!") do endlocal& echo %%K%%~nxL
set "OutputLine=1"
)
)
))>"%FolderPath%\%FolderName%.nfo"
if exist "%FolderPath%\%FolderName%.nfo" echo INFO: Video information written into file: "%FolderPath%\%FolderName%.nfo"
:EndBatch
endlocal
pause
注意: Windows 命令处理器cmd.exe
不适用于处理名称中包含 Unicode 字符的文件名。因此,如果需要一个解决方案真正适用于所有文件名,包括名称中包含 Unicode 字符的文件名,则有必要为该任务编写一个 PowerShell 脚本并使用 powershell.exe
作为脚本解释器。
大多数命令行都在批处理文件本身中使用命令 REM 进行注释。
这里是 FOR 循环的描述,用于处理指定目录中的所有 AVI、MP4、MPG 和 MKV 文件,并使用内部 FOR 循环来运行工具MediaInfo 并通过修改Complete name
的行来处理输出行以删除 Unix/Linux 路径。
最外层的 FOR 在后台启动另外一个带有%ComSpec% /c
的命令进程和带有 DIR 作为附加参数附加的命令行。
命令DIR
在%FolderPath%
引用的目录中搜索
仅用于文件,因为选项 /A-D
(属性不是目录)
匹配四种通配符模式之一*.avi
、*.mp4
、*.mpg
或*.mkv
和
由于选项/B
,仅以裸格式输出不带路径的文件名。
由于上述 IF 条件用于 FOR 循环以在运行 FOR 之前检查是否存在任何视频文件,因此不应输出错误消息 循环。 IF 条件防止在指定目录中创建一个完全不包含视频文件的.nfo
文件。
CMD内部命令DIR处理后台命令进程的STDOUT的输出被for
分别捕获cmd.exe
处理批处理文件并在启动后逐行处理cmd.exe
自行终止。
FOR 带有选项/F
总是忽略空行,这在文件名列表中无关紧要。默认情况下,带有文件名的行将使用普通空格和水平制表符作为字符串分隔符拆分为子字符串。文件名的开头和中间可以包含一个或多个空格。出于这个原因,选项delims=
用于指定一个空的分隔符列表,以防止将文件名拆分为子字符串(令牌)。如果第一个子字符串(标记)以分号开头,则 FOR 也会忽略该行,因为 ;
是默认的行尾字符。文件名可以以;
开头,尽管这很不寻常。因此,选项eol=|
用于将竖线定义为任何文件名都不能包含的行尾字符。 "tokens=*"
没有用,因为它会首先从文件名中删除前导空格,如果剩余的文件名以分号开头,则文件名将被 FOR 忽略。
因此,没有路径的文件名被分配给指定的循环变量I
,即使具有不寻常的名称 ;Video 100% & Test (1)!
。
如果当前处理的文件名不是DIR输出的第一个视频文件名,则输出一个分隔行和两个空行(分别按文件系统排序未排序)。环境变量Separator
在FOR 循环上方明确未定义,并且在外部FOR 循环的每次迭代中(重新)定义。分配给环境变量Separator
的值无关紧要。
请参阅 DosTips 论坛主题 ECHO. FAILS to give text or blank line - Instead use ECHO/,原因是使用 echo(
而不是 echo.
输出空行。
环境变量OutputLine
在运行MediaInfo 之前明确未定义,后来在找到Complete name
的行时定义。它用于在处理完Complete name
行后加速信息行的处理,因为在这种情况下,所有其他行都可以简单地输出而无需任何进一步的特殊处理。
MediaInfo 工具也可以通过在后台启动另一个命令进程来执行,其中%ComSpec% /c
和'
中的命令行作为附加参数附加。因此,了解cmd.exe
如何处理选项/C
之后的参数字符串非常重要。这很棘手,因为参数字符串的处理取决于在命令提示符窗口cmd /?
中运行时的帮助输出所解释的几个条件。在这种情况下,需要将整个命令行包含在"
中,以使用正确的命令行作为参数字符串运行后台命令进程。
但批处理文件也由cmd.exe
处理。所以 FOR 命令行必须包含由后台命令进程以对cmd.exe
都有效的方式执行的命令行。这就是为什么在整个命令行的开头和结尾处的"
以及重定向运算符|
使用^
进行转义,以便cmd.exe
处理批处理文件时将其解释为文字字符。 "
中包含的命令行传递给启动 cmd.exe
不再包含插入符号。
MediaInfo 的输出被重定向到 FINDSTR,它运行一个正则表达式 find 匹配所有行,因此根据选项 @ 输出带有行号和冒号的所有行987654400@。这样做是为了确保 FOR 最终捕获的任何行都不是完全空的行,该行最终也应该在 NFO 文件中,并且不会被 FOR 静默忽略。
MediaInfo 输出的行由FINSTR 扩展,以行号和冒号开头,分别被FOR 捕获cmd.exe
处理批处理文件,并在启动的后台命令进程自行终止后逐行处理。
当前行首先按原样分配给环境变量 InfoLine
,同时禁用延迟扩展以防止将 !
解释为延迟扩展环境变量引用的开始/结束。
接下来启用延迟的环境变量扩展。请阅读 this answer 了解有关命令 SETLOCAL 和 ENDLOCAL 的详细信息,因为在后台发生的不仅仅是启用延迟扩展。
如果已经定义了环境变量OutputLine
,则当前行仅输出,并删除行号和行首的冒号以将该行输出为MediaInfo在后台命令过程中的输出 em>。
否则,将对当前行与所有出现的:Complete name
(行号后面的冒号和字符串:Complete name
)进行区分大小写的字符串比较,该行完全不修改,不区分大小写。如果带字符串替换的行与不带字符串替换的行相同,则来自 MediaInfo 的这一行在开头不包含字符串 Complete name
,因此也只是在删除行号和冒号的情况下输出。
否则带有Complete name
的行会在MediaInfo 的捕获输出中找到。因此,删除开头的行号和冒号的行被分成两个子字符串。第一个子字符串是Complete name
,其中空格和冒号一直到分配给循环变量K
的行中的第一个/
。第二个子字符串是从第一个/
到行尾的所有内容,根据ASCII table(即字母L
)分配给下一个循环变量。
在行首之前先禁用延迟扩展,第三个FOR命令行输出不带路径的文件名。接下来,现在定义环境变量OutputLine
,只输出MediaInfo的所有后续行。
在处理视频文件期间,所有输出到处理批处理文件的命令进程标准输出的所有内容都被重定向到指定文件夹中一个文件夹名称为.nfo
的文件。
媒体信息文件在文件.nfo
上成功,最终存在(并且信息文件在启动批处理文件时不存在,并且还受到只读属性、NTFS 权限或文件访问权限的写保护)。
要了解所使用的命令及其工作原理,请打开command prompt 窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
call /?
cmd /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
批处理文件也可以在 Windows 命令提示符窗口或 PowerShell 控制台中运行,不带或带文件夹路径(也可以是相对路径)。
【讨论】:
以上是关于文件夹内的批处理文件以创建 MediaInfo.nfo 文件的主要内容,如果未能解决你的问题,请参考以下文章
ArcGIS遇上PythonArcGIS Python将多个文件夹内的分幅数据整合到同一个文件夹内——以Globeland30数据为例
ArcGIS遇上PythonArcGIS Python将多个文件夹内的分幅数据整合到同一个文件夹内——以Globeland30数据为例