I have videos files with filenames:
Series.Name.S01E01.andalotofstuff.mkv
Series.Name.S01E02.andalotofstuff.mkv
Series.Name.S02E01.andalotofstuff.mkv
etc.
where andalotofstuff is not necessarily the same in each file, and can include ., - and [].
I also have subtitles files with filenames:
Series Name 1x01 - Episode Name andotherstuff.srt
Series Name 1x02 - Episode Name andotherstuff.srt
Series Name 2x01 - Episode Name andotherstuff.srt
etc.
where andotherstuff is not necessarily the same in each file, and can include ().
What i want is to rename srt files with the corresponding mkv filename with a batch script, if possible, and i have no idea how.
Some real examples are:
Marvels.Agents.of.S.H.I.E.L.D.S05E04.720p.HDTV.x264-AVS[eztv].mkv
Marvel's Agents of S.H.I.E.L.D. 5x04 - A Life Earned (Español (Latinoamérica)).srt
The.Shannara.Chronicles.S02E08.720p.HDTV.x264-AVS[eztv].mkv
The Shannara Chronicles 2x08 - Amberle (Español (España)).srt
The.Shannara.Chronicles.S02E10.720p.HDTV.x264-KILLERS[eztv].mkv
The Shannara Chronicles 2x10 - Blood (English).srt
Note that not necessarily all video files has a corresponding subtitle file.
Here i found something that is supposed to work on linux...
Here is a commented batch file for this task:
#echo off
rem Setup a local environment for this batch file creating lots
rem of environment variables which should not exist anymore after
rem finishing batch file execution.
setlocal EnableExtensions DisableDelayedExpansion
rem Get all *.mkv and *.srt file names in current directory without path
rem and without file extension loaded into memory assigned to environment
rem variables with name mkv_1, mkv_2, ..., srt_1, srt_2, ... using the
rem two subroutines GetFileList and AddFileToList.
call :GetFileList mkv
call :GetFileList srt
goto ValidateFileCounts
rem Subroutine GetFileList runs command FOR which executes command DIR in
rem a separate command process in background which outputs all file names
rem with the file extension passed to the subroutine as first parameter
rem sorted by name. Each file name output by DIR is assigned to an environment
rem variable with passed file extension, an underscore and an incremented
rem number as variable name. The number of files with given file extension
rem is assigned to an environment variable with name FileCount_Extension.
:GetFileList
set "FileNumber=0"
set "FileExtension=%1"
for /F "delims=" %%I in ('dir *.%FileExtension% /A-D /B /ON 2^>nul') do call :AddFileToList "%%~nI"
set "FileCount_%FileExtension%=%FileNumber%"
goto :EOF
rem Subroutine AddFileToList increments current file number by one and then
rem assigns the file name without file extension and without path passed
rem from calling subroutine GetFileList as first and only parameter to
rem an environment variable with automatically generated varible name.
:AddFileToList
set /A FileNumber+=1
set "%FileExtension%_%FileNumber%=%~1"
goto :EOF
rem After creating the two file lists in memory it is validated that the
rem file rename operation can be started at all. There must be *.srt files
rem found in current directory and the number of *.mkv files must be equal
rem the number of *.srt files.
:ValidateFileCounts
if %FileCount_srt% == 0 (
echo/
echo There are no *.srt files in directory:
echo/
echo %CD%
echo/
pause
goto EndBatch
)
if not %FileCount_mkv% == %FileCount_srt% (
echo/
echo Number of *.mkv files is not equal number of *.srt files in directory:
echo/
echo %CD%
echo/
pause
goto EndBatch
)
rem Now delayed environment variable expansion is needed for the file rename
rem operation in a loop which could not be enabled at beginning of the batch
rem file in case of any file name contains one or more exclamation marks.
rem *.srt files having already the same file name as corresponding *.mkv
rem file detected by identical current and new file name are ignored for
rem the rename operation.
rem It is also not possible to rename a *.srt file to name of a *.srt which
rem already exists. In this case an error message is output for the *.srt
rem file which cannot be renamed and finally PAUSE is executed to give the
rem batch file user the possibility to read all those file rename errors.
rem But it is very unlikely that this error message is displayed ever.
setlocal EnableDelayedExpansion
set "RenameError="
for /L %%I in (1,1,%FileCount_srt%) do (
set "FileNameNew=!mkv_%%I!.srt"
set "FileNameNow=!srt_%%I!.srt"
if not "!FileNameNew!" == "!FileNameNow!" (
if not exist "!FileNameNew!" (
ren "!FileNameNow!" "!FileNameNew!"
) else (
echo Rename file !FileNameNow!
echo to new name !FileNameNew!
echo not possible as such a file exists already.
echo/
set "RenameError=1"
)
)
)
if defined RenameError pause
endlocal
rem The previous environment is restored finally which means all environment
rem variables created by this batch file are removed from memory. There is
rem neither a message output nor batch file processing halted if no error
rem occurred during entire process.
:EndBatch
endlocal
There is no real file name matching algorithm used as it looks like the algorithm is human language intelligence. So the batch file just loads into memory the list of *.mkv file names sorted by name and the list of *.srt file names also sorted by name and then renames first *.srt file to name of first *.mkv file, second *.srt file to name of second *.mkv file, and so on. This simple solution worked for the given examples.
It is possible to insert the command echo left to command ren and append command pause at end of the batch file or run it from within a command prompt window to see all the file rename operations without really doing them for verification by user before really renaming the *.srt files.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
rem /?
ren /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
Read this answer for details about the commands SETLOCAL and ENDLOCAL and Where does GOTO :EOF return to?
In Windows you can do it with program called "Subtitle And Video Renamer". I just tested version 0.5.1 and I renamed ~30 subtitles with 2 buttons click.
Related
The code below should archive some files by moving them into a subfolder. The batch file asks the user for the folder path. Then a subfolder should be created and if that was successful, it should move all files in the user input directory into the subdirectory. It works, but it closes although using pause. It does not output anything about a syntax error or anything at all. Please let me know if somebody notices something.
#echo off
SETLOCAL EnableDelayedExpansion
echo Insert path:
set /p path=
echo the path is %path%
cd %path%
echo The files will be moved to a new folder
pause
mkdir %path%\archived_files
IF EXIST "archived_files" (
for /f %%A in ('DIR /A /D /B') do (
echo %%A && move /Y %path%\%%A %path%\archived_files)
echo Folder "archived_files" created or already exists
) else ( echo Folder "archived_files" does not exist )
echo the files have been transferred
pause
ENDLOCAL
I suggest to use this batch file for the file moving task.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BatchFileName=%~nx0"
set "BatchFilePath=%~dp0"
set "UserPath=%~1"
if defined UserPath goto ChangeFolder
:UserPrompt
set "UserPath="
set /P "UserPath=Enter path: "
rem Has the user not entered a string?
if not defined UserPath goto UserPrompt
rem Remove all double quotes from input string.
set "UserPath=%UserPath:"=%"
rem Has the user entered just one or more double quotes?
if not defined UserPath goto UserPrompt
:ChangeFolder
pushd "%UserPath%" 2>nul || (echo Folder "%UserPath%" does not exist.& goto UserPrompt)
for /F "eol=| delims=" %%I in ('dir /A-D /B 2^>nul') do goto CreateSubfolder
echo The folder does not contain any file to archive.& goto EndBatch
:CreateSubfolder
md "archived_files" 2>nul
if not exist "archived_files\" echo Failed to create subfolder: "archived_files"& goto EndBatch
rem It must be avoided that the currently running batch file is moved too.
set "ExcludeFileOption="
for %%I in ("%UserPath%\") do set "CurrentFolderPath=%%~dpI"
if "%CurrentFolderPath%" == "%BatchFilePath%" set "ExcludeFileOption= /XF "%BatchFileName%""
rem The command MOVE used with wildcard * does not move hidden files. A FOR loop
rem with MOVE is slow in comparison to usage of ROBOCOPY to move really all files.
rem The ROBOCOPY option /IS can be removed to avoid moving same files existing
rem already in the subfolder archived_files from a previous batch execution.
echo The files are moved to a new folder.
%SystemRoot%\System32\robocopy.exe . archived_files%ExcludeFileOption% /MOV /R:2 /W:5 /IS /NDL /NFL /NJH /NJS
if not errorlevel 2 if errorlevel 1 echo All files are moved successfully.
:EndBatch
popd
endlocal
pause
The batch file can be started with a a folder path as argument. So it is possible to right click on the batch file and click in opened context menu in submenu Send to on item Desktop (create shortcut). The .lnk file created on the user´s desktop can be renamed now also via context menu or key F2 to whatever name is useful like Archive files. Then the shortcut file can be cut with Ctrl+X and pasted with Ctrl+V in the folder %APPDATA%\Microsoft\Windows\SendTo to have in Send to context submenu the menu item Archive files. This makes it possible to right click on a folder and click in opened context menu in submenu Send to on Archive files to run the batch file without the need to enter a folder path manually.
The batch file prompts the user for the path if not started with a folder path as first argument or the folder cannot be found at all. This user prompt is done using a safe method. The batch file makes the passed or entered folder temporarily the current folder for the remaining commands using PUSHD and POPD instead of CD to work also with UNC paths.
There is checked next if the folder contains any file at all. Otherwise the user is informed that the directory does not contain files to archive and batch file ends without any further action.
The file movement is done with ROBOCOPY for the reasons described in a remark in the batch file which requires Windows Vista or a newer Windows version or Windows Server 2003 or a newer Windows server version.
I recommend to see also:
Debugging a batch file which answers your question.
What is the reason for "X is not recognized as an internal or external command, operable program or batch file"? It explains why path as name for the environment variable to assign the user entered path is a really bad idea.
How to stop Windows command interpreter from quitting batch file execution on an incorrect user input? It explains the reasons for using the additional code to evaluate the string entered by the user.
Why is no string output with 'echo %var%' after using 'set var = text' on command line? It explains the recommended syntax for the (re)definition of an environment variable and why using this syntax.
Syntax error in one of two almost-identical batch scripts: ")" cannot be processed syntactically here describes several common issues made by beginners in batch file coding like not enclosing a file/folder path in double quotes.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~nx0, %~dp0 and %~1 whereby argument 0 is always the batch file itself.
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
pause /?
popd /?
pushd /?
rem /?
robocopy /?
set /?
setlocal /?
Other useful documentations used to write this code:
single line with multiple commands using Windows batch file
the Microsoft documentations for the used Windows Commands
the SS64 documentations for the used Windows CMD commands, especially:
ROBOCOPY.exe
ROBOCOPY Exit Codes
the Microsoft documentation about Using command redirection operators
and the SS64 documentation How-to: Redirection
Note: The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background with %ComSpec% /c and the command line within ' appended as additional arguments.
Been trying to create an additional batch script that processes files for me. I either get send 1 or several .pdf test files in a .rar file.
So what I am trying to aim for is:
If the first variable 1 is named 'test' then
Is there a .rar file in the folder from variable 2 then
Extract to a folder and then delete .rar file
else
check that there is a .pdf file and then copy to folder
Else
Tell the user that neither a file or a archive has been found
I've managed to scrape this together but I need help trying to expand it further to include all the options:
#echo off
set "cat=%1"
IF "%cat%"=="test" ( for /f %%G in ('dir *.rar /b') do set filename=%%~G)
echo %filename%
This only gives me half the file name as they have gaps in the filename, also need to change the dir in the 3rd line to be looking in variable 2 that is sent in.
To add to it I've just been told that it's the same for .txt files, the multiples are sent to me in a .rar file
I suggest to open a command prompt, run call /? and read the output help. The help explains how the arguments – also called options or parameters, but not variables – of a batch file can be referenced from within a batch file.
It is advisable to check if a batch file is called with at least one argument if it must be called with at least one argument and output a help for correct usage of the batch file if it was started without any argument or if it was started with /? which is the default on Windows to get help about a command or program.
The manual for console version of WinRAR is the file Rar.txt in program files folder of WinRAR. It can be read in this text file after opening it with a double click that Rar.exe can extract one or more *.rar archive files found in a directory. For that reason it is not really necessary to use command FOR. But it is advisable for this task to use command FOR as the RAR file(s) should be deleted after successful extraction of the RAR archive(s).
Let us look on the FOR command line for /f %%G in ('dir *.rar /b') do and what it does on execution.
FOR with option /F to process a text file content or a single string or the output of a command line results in this case in starting a command process in background with %ComSpec% /c and the command line between the two ' appended. So executed by the Windows command process cmd.exe processing the batch file with for /F is the following with Windows installed into C:\Windows as by default:
C:\Windows\System32\cmd.exe /c dir *.rar /b
The command DIR executed by separate command process in background
searches in current directory
for directory entries (files or directories)
matching the wildcard pattern *.rar
and not having hidden attribute set (implicit default is /A-H on option /A not specified at all)
and outputs to handle STDOUT the found directory entries matching the criteria above in bare format line by line which means with just file/folder name without path and never enclosed in double quotes even on containing a space or one of these characters &()[]{}^=;!'+,`~.
An error message is output by DIR to handle STDERR of background command process if it cannot find any directory entry matching the search criteria.
FOR respectively the command process processing the batch file redirects the output to handle STDERR of the background command process to its own STDERR handle which results in getting it displayed in console window in this case. But the output to handle STDOUT of started background command process is captured by FOR respectively the command process processing the batch file and is processed line by line after started background command process terminated itself.
FOR used with option /F always ignores empty lines. This does not matter here because of DIR does not output empty lines on being executed with option /B.
for /F splits up a non-empty line by default into substrings using normal space and horizontal tab as string delimiters and assigns by default just first space/tab separated string to the specified loop variable which is here the loop variable G. for /F ignores by default additionally also a processed line if the first substring after splitting the line up starts with a semicolon because of eol=; is the default for end of line option.
So the command line for /f %%G in ('dir *.rar /b') do causes several problems on processing the list of directory entries output by DIR.
For a file/folder name containing a space just the first space/tab separated part of the file/folder name is assigned to loop variable G instead of complete name. For example a name like My Archive.rar results in just My is assigned to the loop variable G.
A file/folder name with one or more leading spaces is assigned to loop variable G without those leading spaces which means again that G does not hold complete name. For example a name like TwoLeadingSpaces.rar results in getting assigned to loop variable G just TwoLeadingSpaces.rar without the two leading spaces and the file (or folder) is not found on referencing the value of loop variable G.
A file/folder name with a semicolon at beginning after zero or more leading spaces is completely ignored by command FOR for further processing. For example names like ;Test.rar (name beginning with a semicolon) or ;TestWithALeadingSpace.rar (name with leading space and a semicolon) are completely ignored for further processing by FOR.
The points 2 and 3 are usually no problem as file/folder names with leading space(s) or a semicolon at beginning are really very rare. But a file/folder name with a space occurs very often.
A solution would be using FOR without option /F:
for %%G in (*.rar) do
FOR searches now itself for non-hidden files (not directories) in the current directory matching the wildcard pattern *.rar and assigns a found file name without path to loop variable G and next runs the command(s) after do. There is no additional command process started and there is no substring splitting done.
But there is a problem with this very simple solution in case of the commands executed for each found file name delete, move or rename files matched by the wildcard pattern *.rar. The list of directory entries matching the wildcard pattern changes on each iteration of the body of the FOR loop while command FOR queries the directory entries one after the other with executing the commands between each directory query. This is especially on FAT16, FAT32 and exFAT drives a real problem, but can result also in unexpected behavior on NTFS drives.
Whenever a FOR loop is used to process a list of files which could change during the iterations of the loop because of deleting, moving or renaming the files matched by a wildcard pattern, it is better to process a list of files loaded completely into memory before first iteration of the loop.
So a better solution for this task with the requirement to delete a RAR archive file after successful extraction is:
for /F "eol=| delims=" %%I in ('dir *.rar /A-D /B 2^>nul') do
The DIR option /A-D results in ignoring directory entries with attribute directory. So output by DIR are just file names matching the wildcard pattern in current directory including hidden RAR archive files.
2^>nul is passed as 2>nul to the background command process which results in redirecting the error message output by DIR on no *.rar file found to device NUL to suppress it.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
The for /F option eol=| changes the end of line character from ; to |. No file name can have a vertical bar in its file name according to Microsoft documentation about Naming Files, Paths, and Namespaces. So no file name is ignored anymore by FOR because of end of file option.
The for /F option delims= changes the delimiters list for line splitting into substrings to an empty list of delimiters which disables the line splitting behavior completely. So a file name with one or more spaces anywhere in file name is assigned completely to the specified loop variable I.
The task description is not very clear regarding to what to do depending on the batch file arguments, especially if the first argument is not case-insensitive test.
However, the following commented batch file could be working for this task on being called with first argument being test or with no arguments at all or with /? as first argument.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" goto OutputHelp
if "%~1" == "/?" goto OutputHelp
if /I not "%~1" == "test" goto MoreCode
set "SourceFolder=%~2"
if defined SourceFolder goto CheckFolder
echo/
echo Error: Folder with RAR or PDF file(s) not specified on command line.
goto OutputHelp
:CheckFolder
rem Replace all forward slashes by backslashes in folder name.
set "SourceFolder=%SourceFolder:/=\%"
rem Append a backslash to folder path if it does not end with a backslash.
if not "%SourceFolder:~-1%" == "\" set "SourceFolder=%SourceFolder%\"
rem Check the existence of the source folder.
if exist "%SourceFolder%" goto ProcessFolder
echo/
echo Error: Folder "%SourceFolder%" does not exist.
goto OutputHelp
:ProcessFolder
rem Get full qualidfied folder name, i.e. the folder name
rem with its absolute path and ending with a backslash.
for %%I in ("%SourceFolder%") do set "SourceFolder=%%~fI"
rem Define the destination folder for the PDF files extracted from the
rem RAR archive file(s) in source folder or copied from source folder.
set "DestinationFolder=C:\Temp\Test\"
rem Search for all *.rar files in folder passed with second argument and
rem extract all *.pdf files in each RAR archive file to the configured
rem destination folder. Rar.exe creates the destination folder automatically
rem if it is not already existing. The batch file is halted after processing
rem a RAR file on which Rar.exe exited with a value greater 0. Read the exit
rem codes documentation of Rar.exe at bottom of text file Rar.txt for more
rem information about the RAR exit codes. See Rar.txt also for the meaning
rem of the few RAR switches used here.
set "RarFileCount=0"
for /F "eol=| delims=" %%I in ('dir "%SourceFolder%*.rar" /A-D /B 2^>nul') do (
set /A RarFileCount+=1
"%ProgramFiles%\WinRAR\Rar.exe" e -cfg- -idcdp -or -- "%SourceFolder%%%I" *.pdf "%DestinationFolder%"
if not errorlevel 1 (del /A /F "%SourceFolder%%%I") else echo/& pause
)
if %RarFileCount% == 0 goto CheckFiles
if %RarFileCount% == 1 (set "PluralS=") else set "PluralS=s"
echo/
echo Info: Processed %RarFileCount% *.rar file%PluralS% in folder "%SourceFolder%".
goto EndBatch
:CheckFiles
echo Info: There are no *.rar files in folder "%SourceFolder%".
if exist "%SourceFolder%*.pdf" goto CopyFiles
echo Info: There are no *.pdf files in folder "%SourceFolder%".
goto EndBatch
:CopyFiles
rem Copy all PDF files in source folder to destination folder. xcopy.exe
rem creates destination folder automatically if it is not already existing.
echo/
%SystemRoot%\System32\xcopy.exe "%SourceFolder%*.pdf" "%DestinationFolder%" /C /I /Y
goto EndBatch
:OutputHelp
echo/
echo Usage: %~n0 [TEST] [Folder with RAR or PDF file(s)]
echo/
echo If the first argument is case-insensitive TEST, the second argument
echo specifies the folder containing the RAR files to extract or the PDF
echo files to copy to destination folder. The folder must be specified
echo with first argument being TEST.
echo/
pause
goto EndBatch
:MoreCode
rem Add here the code to execute on first argument is not case-insensitive TEST.
:EndBatch
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
del /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
xcopy /?
"%ProgramFiles%\WinRAR\Rar.exe" /?
You can use this:
#echo off
set "cat=%~1"
IF "%cat%"=="test" (
for %%G in (*.rar) do set filename=%%G
)
echo %filename%
Here wildcard is used to get all the rar files in the directory.
My question is related to: Batch Rename contents of ZIP file to ZIP file name
But I am looking for a simpler batch file, as I do not understand that very well.
I have about 600 .7z files. I want these 7z files names to match a .cue file contained in each of the .7z file.
To make it more clear, I give an example below:
File Crash Bandicot PSX 1995.7z contains:
Crash Bandicot (USA) track 1.bin
Crash Bandicot (USA) track 2.bin
Crash Bandicot (USA) track 3.bin
Crash Bandicot (USA).cue
I would like to rename the .7z name to match the .cue file (preferably). Like this:
Crash Bandicot (USA).7z still containing:
Crash Bandicot (USA) track 1.bin
Crash Bandicot (USA) track 2.bin
Crash Bandicot (USA) track 3.bin
Crash Bandicot (USA).cue
Could someone help me out to make a batch to do this?
Edit:This is the script code I have so far:
FOR /r %%i IN (*) DO "C:\Program Files (x86)\7-Zip\7z.exe" a "%%~ni.7z" "%%i"
First, I suggest opening help file 7zip.chm in program files directory of 7-Zip with a double click. Open on Contents tab the list item Command Line Version and next the list item Commands and click on l (List) to open the help page for listing archive file contents.
The batch file below uses 7-Zip with the command l with the switches -i (include) and -slt (show technical information). The batch file expects to find the *.cue file in root of each *.7z archive file and therefore does not use the option to search for *.cue files in archive recursively.
Second, open a command prompt window in directory containing the about 600 *.7z archive files and run the command line:
"%ProgramFiles(x86)%\7-Zip\7z.exe" l -i!*.cue -slt "Crash Bandicot PSX 1995.7z"
7-Zip outputs the list of *.cue files inside archive Crash Bandicot PSX 1995.7z with showing technical information. Now with knowing how the output of 7-Zip (of version 16.04 as used by me) looks like, the options used in batch file for second FOR loop can be understood better.
The batch file below searches only in current directory for *.7z files and renames all files containing a *.cue file if name does not already match.
Insert DIR option /S (search also in subdirectories) after /B (bare format) in case of the *.7z files are not all in current directory, but in current directory and its subdirectories.
Here is the comment batch file for this archive file renaming task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Prepend folder path to 7z.exe temporarily to local copy of environment
rem variable PATH to be able to call 7z.exe without full path enclosed in
rem double quotes as this would make the FOR command line running 7z.exe
rem really very difficult.
set "PATH=%ProgramFiles(x86)%\7-Zip;%PATH%"
set "PauseOnWarning=0"
rem Search in current directory for *.7z files using command DIR and not FOR
rem directly and call for each found file the subroutine RenameArchiveFile
rem with file name enclosed in double quotes. It is important not using FOR
rem for searching for *.7z files as the found *.7z files are renamed while
rem executing the loop. A *.7z file could be easily processed more than once
rem on using command FOR directly. Better is in this case to use command DIR
rem which first search for all *.7z files (including hidden ones which FOR
rem would not do) and then outputs the names of all found files being
rem processed next by command FOR. So it does not matter that file names
rem change while FOR processes the list of file names output by DIR.
for /F "delims=" %%I in ('dir /A-D /B *.7z 2^>nul') do call :RenameArchiveFile "%%I"
rem Output an empty line and halt batch file execution if any warning
rem was output while processing the *.7z files in the subroutine.
if %PauseOnWarning% == 1 echo/ & pause
rem Restore previous command line environment and exit batch processing.
endlocal
goto :EOF
rem RenameArchiveFile is a subroutine called with name of the archive file
rem enclosed in double quotes. The file name can be with or without path.
rem 7-Zip is executed to output the list of *.cue files with showing
rem technical information for easier parsing the output lines. Any error
rem message output by 7-Zip is suppressed by redirecting them from STDERR
rem to device NUL. It is not expected that 7-Zip outputs an error at all.
rem The first 14 lines are always skipped by command FOR. The next lines
rem are split up into two substrings using space and equal sign as string
rem delimiters. The first substring is assigned to loop variable A and
rem everything after first substring and 1 to n spaces/equal signs is
rem assigned to loop variable B. There is hopefully no *.cue file which
rem begins unusually with an equal sign or a space character.
rem If the first substring (token) from current line assigned to loop
rem variable A is case-sensitive the word Path, it is expected that the
rem second substring (token) assigned to loop variable B is the name of
rem the *.cue file found in the current archive file. In this case the
rem file name is assigned to an environment variable and loop is exited
rem with a jump to label HaveFileName.
rem A warning message is output if no *.cue file could be found in archive.
:RenameArchiveFile
for /F "skip=14 tokens=1* delims== " %%A in ('7z.exe l -i!*.cue -slt %1 2^>nul') do (
if "%%A" == "Path" (
set "FileName=%%B"
goto :HaveFileName
)
)
echo Warning: Could not find a *.cue file in: %1
set "PauseOnWarning=1"
goto :EOF
rem A *.cue file was found in current archive. The file extension cue
rem at end is replaced by 7z for the new name of the archive file.
rem First it is checked if the current archive file has already the file
rem name of the *.cue file inside the archive in which case the subroutine
rem RenameArchiveFile is exited resulting in processing of batch file being
rem continued on main (first) FOR loop.
rem If there is no *.7z file in directory of current archive file with
rem the new name, the current archive file is renamed to new name and
rem subroutine RenameArchiveFile is exited without further processing.
rem But if a different archive file than current archive file has already
rem the new archive file name, the subroutine outputs a 3 lines warning
rem and exits without renaming the current archive file. The user has to
rem handle this file name collision.
:HaveFileName
set "FileName=%FileName:~0,-3%7z"
if "%FileName%" == "%~nx1" goto :EOF
if not exist "%~dp1%FileName%" ren %1 "%FileName%" & goto :EOF
echo Warning: Could not rename %1
echo to "%FileName%"
echo because a file with that name already exists.
set "PauseOnWarning=1"
goto :EOF
It might be a good idea to first insert command echo left of rename command ren near and of the batch file and insert pause in a line between endlocal and goto :EOF to test how the *.7z files would be renamed without really doing it.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
7z ... 7-Zip is not using standard Windows syntax for options, but outputs a brief help on running without any parameter or with just -h as parameter.
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
rem /?
ren /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul used in this batch file twice with escaping the redirection operator > with caret character ^ to get > interpreted as literal character on parsing FOR command line by Windows command interpreter and later on execution of DIR command line by FOR as redirection operator.
And see Single line with multiple commands using Windows batch file for understanding what an ampersand & means in command lines if not being present within a double quoted string.
I have a folder structure like below:
D:\folder
test1
opt
test1.zip (10 MB)
test1.zip (100 MB)
test2
opt
test2.zip (10 MB)
test2.zip (100 MB)
test3
opt
test3.zip (10 MB)
test3.zip (100 MB)
Same files in a flat list:
D:\folder\test1\test1.zip
D:\folder\test1\opt\test1.zip
D:\folder\test2\test2.zip
D:\folder\test2\opt\test2.zip
D:\folder\test3\test3.zip
D:\folder\test3\opt\test3.zip
I have a script that optimizes zip files. What I need to do in a batch file is to basically find these optimized files in opt folders and overwrite the larger version with the smaller one.
Take a look on this commented batch code:
#echo off
for /D %%I in ("D:\folder\*") do (
if exist "%%I\%%~nxI.zip" (
if exist "%%I\opt\%%~nxI.zip" (
call :CompareFiles "%%I\%%~nxI.zip" "%%I\opt\%%~nxI.zip"
)
)
)
goto :EOF
rem The loop runs on each subdirectory of directory D:\folder. It first
rem checks if there is a *.zip file in the subdirectory with same name as
rem the subdirectory. Next it checks if in the current subdirectory there
rem is a subdirectory with name "opt" with having also a *.zip file with
rem same name as the subdirectory. If this second condition is also true,
rem the subroutine CompareFiles is called with the names of the 2 ZIP files.
rem The subroutine compares the file size of the two ZIP files.
rem The optimized ZIP file is moved over the ZIP file in directory
rem above if being smaller than the ZIP file in directory above.
rem Otherwise the optimized ZIP file being equal or greater as the
rem ZIP file above is deleted.
rem Finally the subdirectory "opt" is deleted which works only if the
rem subdirectory is empty. The error message output by command RD in
rem case of "opt" is not empty is redirected from STDERR to device NUL
rem to suppress it.
rem goto :EOF above results in exiting processing this batch file after
rem finishing the loop and avoids a fall through to the subroutine. The
rem goto :EOF below would not be really necessary as it is at end of the
rem batch file. But it is recommended to end each subroutine with goto :EOF
rem or alternatively exit /B in case of one more subroutine is added later.
:CompareFiles
if %~z1 GTR %~z2 (
move /Y %2 %1
) else (
del /F %2
)
rd "%~dp2" 2>nul
goto :EOF
You can test the batch file by inserting command echo left to the commands move and del and run the batch file from within a command prompt window to see the output. When the result is as expected, run the batch file once again without the two added echo.
ATTENTION:
Windows command processor supports only signed 32-bit integer numbers. So this batch code does not work for ZIP files with 2 GiB (= 2.147.483.650 bytes) or more.
%%~nxI references usually file name and file extension. Windows command processor interprets everything after last backslash as name of a file or directory. Here the string assigned to loop variable I is the name of the subdirectory with drive and path D:\folder\ not ending with a backslash. For that reason %%~nI references the name of the current subdirectory in D:\folder\. The file extension is defined as everything after last point. Directories usually don't have a point in directory name and so %%~nI is often also enough for a directory name. But it is possible to create directories also with a point in directory name. Therefore using %%~nxI is more safe as working for any directory name.
Note: Subdirectories with hidden or system attribute are ignored by command FOR.
It is 100% safe to use just %1 and %2 in subroutine CompareFiles instead of "%~1" and "%~2" as both file names must be passed already enclosed in double quotes to the subroutine on containing a space or one of these characters: &()[]{}^=;!'+,`~. So it does not make sense from an execution point of view to specify on move and del the arguments (file names) with "%~1" and "%~2". But it is of course possible to use "%~1" and "%~2" for example for better syntax highlighting in text editor or for uniformed file name references passed as arguments to a batch file or subroutine.
The batch file can be simplified on not testing if the two ZIP files exist at all and the optimized ZIP file is really smaller.
#echo off
for /D %%I in ("D:\folder\*") do (
move /Y "%%I\opt\%%~nxI.zip" "%%I\%%~nxI.zip" 2>nul
rd "%%I\opt" 2>nul
)
The error message output in case of optimized ZIP file not existing is suppressed by redirecting it to device NUL.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
del /?
echo /?
for /?
goto /?
if /?
move /?
rd /?
See also the Microsoft article Using command redirection operators for details on 2>nul.
My requirement is - i need to read the filename from an input folder say - C:\Encrypt\In and pass it to the command java.exe -jar D:\SYS\src\PI\IN\Cryptage.jar -rc4 -crypt D:\SYS\src\PI\IN\Decrypt\ D:\src\PI\IN\Encrypt\ %VAR1%%VAR2%
i tried doing the one below - but no luck
set VAR1=FOR /R C:\Encrypt\In %F in (*.*) do echo %~nF
set VAR2=ABCD
echo %VAR1%%VAR2% (concatenate the filename with "ABCD" as constant)
java.exe -jar D:\SYS\src\PI\IN\Cryptage.jar -rc4 -crypt D:\SYS\src\PI\IN\Decrypt\ D:\src\PI\IN\Encrypt\ %VAR1%%VAR2%
(pass it here - so that each time a file comes in the input directory the variables can pick up the file names dynamically through the variables)
echo %VAR1%%VAR2% is not working.
Thanks anyway - i achieved it through this :- cd C:\Encrypt\In\ for %%f in (.) do ( rem echo %%~nfAPSI set v=%%~nfAPSI ) echo %v%
Here is a commented batch code for your task:
#echo off
set "ScanFolder=C:\Encrypt\In"
rem The loop runs command DIR to get a list of files with archive attribute set.
rem Directories are ignored even if archive attribute is set on a directory.
rem On each file with archive attribute currently set the archive attribute
rem is removed from file and then the command is started to process the file.
rem After all files with archive attribute were processed, the batch file
rem waits 5 seconds before scanning the folder again. The loop is infinite
rem and can be breaked only by pressing Ctrl+C or closing command prompt
rem window to stop command line interpreter.
:Loop
for /F "delims=" %%F in ('dir /AA-D /B "%ScanFolder%" 2^>nul') do (
%SystemRoot%\System32\attrib.exe -A "%ScanFolder%\%%~nxF"
java.exe -jar D:\SYS\src\PI\IN\Cryptage.jar -rc4 -crypt D:\SYS\src\PI\IN\Decrypt\ D:\src\PI\IN\Encrypt\ "%ScanFolder%\%%~nxF"
)
%SystemRoot%\System32\ping.exe -n 6 127.0.0.1>nul
goto Loop
java.exe should be called with full path enclosed in double quotes if possible as in this case command line interpreter would not always need to search for it in the folders of environment variable PATH.
Note: The batch file calls the new file with full path, file name and extension without anything appended. Of course you can replace %%~nxF at end of line calling java.exe also with %%~nFABCD if this is necessary in your environment.
For an explanation of the used commands and how they work in detail open a command prompt window and execute following commands to see the help of those commands:
attrib /?
dir /?
for /?
ping /?