1. Windows CMD versus PowerShell
The Windows command processor (cmd.exe
) is processing a batch file. Its successor is the much more powerful script interpreter PowerShell (powershell.exe
). The usage of PowerShell within a batch file does not really make sense as in this case it would be better to do the entire task with a PowerShell script using PowerShell syntax. For that reason I wrote a pure Windows command processor solution.
2. File/folder name not enclosed in double quotes
A file/folder name should be always referenced enclosed in "
as otherwise a batch file could fail to process file/folder names containing a space or one of these characters &()[]{}^=;!'+,`~
. Most argument strings referencing a file or folder name are enclosed in double quotes in code posted in question, but some are not.
See: Syntax error in one of two almost-identical batch scripts: “)” cannot be processed syntactically here
3. Wrong usage of command DIR
The first FOR loop is not working as it should:
FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (
The command DIR is executed by one more command process started in background with %ComSpec% /c
and the command line within '
appended as additional arguments to output in bare format (just file/folder name without path) all files/folders in directory specified with %~f1
and all files/folders matching the pattern *.mkv
in current directory on batch file execution. That is not correct. Correct would be dir "%~f1\*.mkv" /A-D /B
to output just the names of all files with file extension .mkv
in the directory referenced with %~f1
.
The two file not found error messages are output most likely because of no *.mkv
file/folder is found in the current directory whatever is the current directory on execution of the batch file.
The file names are output by DIR without path, except option /S
is used for a recursive search. That must be taken into account on processing the file names output by DIR which is not done in batch code posted in the question.
4. Enabled delayed expansion not good on processing file names with a FOR loop
Enabling delayed expansion above a FOR loop processing file names, or lines in a text file, or lines captured from standard output of a command process executed in background, is not good because it results in parsing a command line within the command block executed by FOR for each file name a second time before execution. A file/folder name or line containing one or more exclamation mark is not correct processed in this case because of !
is interpreted by cmd.exe
on second parsing as start/end of a delayed expanded environment variable reference and not as literal character of file name or line.
See: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
5. cat is not a Windows command
cat
is not a Windows command. That is a tool ported from Unix/Linux to Windows or executed on Windows 10 using Subsystem for Linux (WSL).
For that reason it is better to avoid the usage of cat
as not available by default on Windows depending on version of Windows and user´s configuration.
6. Command CALL is of no use on running an executable
The command CALL is of no use on running an executable from within a batch file. It is the default behavior of Windows command processor to run the executable and wait for self-termination before processing the next command line in batch file.
The command CALL is mainly needed for calling a batch file from within a batch file.
The usage of command CALL on a command line just running an executable makes the processing of the batch file just slower because of cmd.exe
processes in this case the command line a second time similar to usage of delayed expansion before executing the command line.
7. Batch file for collecting video information in one .nfo file
I don't have the tool MediaInfo installed nor do I have MKV files or other video files. It is perhaps enough to make the directory of which path is passed to the batch file the current directory and run MediaInfo.exe
with just name of a video file in that directory to get the Complete name
information written into the file without path. MediaInfo seems to be a tool ported also from Unix/Linux as it outputs the complete name of the video file without drive letter and colon and with /
instead of \
. The backslash is the directory separator on Windows as it can be read in the Microsoft documentation about Naming Files, Paths, and Namespaces.
Batch file code not using PowerShell or 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
ATTENTION: The Windows command processor cmd.exe
is not designed for processing file names with Unicode characters in name. So if a solution is needed to work really for all file names including those with Unicode characters in name, it is necessary to code a PowerShell script for the task and use powershell.exe
as script interpreter.
Most command lines are explained with remarks using command REM in the batch files itself.
Here is a description of the FOR loop for processing all AVI, MP4, MPG and MKV files in specified directory with an inner FOR loop to run the tool MediaInfo and process the output lines with modification of the line with Complete name
to remove the Unix/Linux path.
The most outer FOR starts in background one more command process with %ComSpec% /c
and the command line with DIR appended as additional arguments.
The command DIR
- searches in the directory referenced with
%FolderPath%
- just for files because of option
/A-D
(attribute not directory)
- matching one of the four wildcard patterns
*.avi
,*.mp4
, *.mpg
or *.mkv
and
- outputs just the file names without path in bare format because of option
/B
.
There should not be an error message output because of the IF condition used above to FOR loop to check the existence of any video file before running the FOR loop at all. The IF condition prevents the creation of an .nfo
file in the specified directory on not containing a video file at all.
The output of CMD internal command DIR to handle STDOUT of background command process is captured by for
respectively cmd.exe
processing the batch file and processed line by line after started cmd.exe
terminated itself.
FOR with option /F
ignores always empty lines which does not matter here on file names list. A line with a file name would be split up by default into substrings using normal space and horizontal tab as string delimiters. A file name can contain one or more spaces at beginning and also in the middle. For that reason option delims=
is used to specify an empty list of delimiters to prevent splitting up the file name into substrings (tokens). If the first substring (token) starts with a semicolon, the line is also ignored by FOR because of ;
is the default end of line character. A file name can have ;
at beginning although this is very unusual. Therefore option eol=|
is used to define a vertical bar as the end of line character which no file name can contain ever. "tokens=*"
is not useful as it results in removing first a leading spaces from file name and if the remaining file name starts with a semicolon, the file name is ignored by FOR.
So a file name without path is assigned to the specified loop variable I
, even on having the unusual name ;Video 100% & Test (1)!
.
A separator line and two empty lines are output if the currently processed file name is not the name of the first video file output by DIR (unsorted respectively as sorted by the file system). The environment variable Separator
is explicitly undefined above the FOR loop and is (re)defined on each iteration of the outer FOR loop. The value assigned to the environment variable Separator
does not matter.
See DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for the reason using echo(
instead of echo.
to output empty lines.
The environment variable OutputLine
is explicitly undefined before running MediaInfo and is later defined on having found the line with Complete name
. It is used to speed up the processing of the information lines once the line Complete name
was processed as in this case all other lines can be simply output without any further special processing.
The tool MediaInfo is executed also by starting in background one more command process with %ComSpec% /c
and the command line within '
appended as additional argument. For that reason it is very important to know how cmd.exe
processes the argument string(s) after option /C
. That is tricky as the processing of the argument string(s) depends on several conditions explained by the help output on running in a command prompt window cmd /?
. In this case it is necessary to enclose the entire command line in "
to run background command process with correct command line as argument string.
But the batch file is processed also by cmd.exe
. So the FOR command line must contain the command line to execute by background command process in a manner being valid for both cmd.exe
. This is the reason why "
at beginning and at end of the entire command lines and also the redirection operator |
are escaped with ^
to be interpreted as literal characters by cmd.exe
processing the batch file. The command line enclosed in "
passed to started cmd.exe
does not contain the caret characters anymore.
The output of MediaInfo is redirected to FINDSTR which runs a regular expression find matching all lines and therefore outputs all lines with a line number and a colon according to option /N
. This is done to make sure no line captured finally by FOR is a completely empty line which should be finally also in the NFO file and not silently ignored by FOR.
The lines output by MediaInfo extended by FINSTR with a line number and a colon at beginning are captured by FOR respectively cmd.exe
processing the batch file and are processed line by line after started background command process terminated itself.
The current line is first assigned as is to the environment variable InfoLine
while delayed expansion is disabled to prevent interpretation of !
as start/end of a delayed expanded environment variable reference.
Delayed environment variable expansion is enabled next. Please read this answer for details about the commands SETLOCAL and ENDLOCAL as there happens more in the background than just enabling delayed expansion.
The current line is just output if the environment variable OutputLine
is defined already with removal of the line number and the colon at beginning of the line to output the line as output in background command process by MediaInfo.
Otherwise there is made a case-sensitive string comparison of the current line with all occurrences of :Complete name
(colon after line number and the string :Complete name
) removed case-insensitive with the line not modified at all. If line with string substitution is equal the line without string substitution, this line from MediaInfo does not contain at beginning the string Complete name
and is therefore also just output with removal of line number and colon.
Otherwise the line with Complete name
is found in captured output of MediaInfo. For that reason the line with line number and colon at beginning removed is split up into two substrings. The first substring is Complete name
with the whitespaces and the colon up to first /
in the line which is assigned to loop variable K
. The second substring is everything after first /
up to end of the line which is assigned to next but one loop variable according to the ASCII table which is the letter L
.
Delayed expansion is disabled first before the beginning of the line and the file name without path are output by the third FOR command line. Next the environment variable OutputLine
is defined now to just output all further lines of MediaInfo.
Everything output to standard output of command process processing the batch file during processing the video files is redirected into a file with folder name with file extension .nfo
in the specified folder.
The media information file was successful on file .nfo
finally existing (and the information file did not exist already on starting the batch file and was additionally write-protected by read-only attribute, NTFS permissions or file access permissions).
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
call /?
cmd /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
The batch file can be run also from within a Windows command prompt window or PowerShell console without or with a folder path which can be also a relative path.