In Windows, I have a batch file for processing the text file C:\BBB\CCC\list.txt for deciding which files to move. It should move all the files that are in a folder (%folder%) and its subfolders, but only if:
- in the name of the folder there is not the year set in input (
%excludeName%) - that file is not listed in a text file (
%excludeFile%).
In that list.txt I have millions of rows like:
C:\AAA\XXX\ZZZ\image_1.jpg
C:\AAA\XXX\KKK\image_2.jpg
C:\AAA\XXX\ZZZ\pdf_1.pdf
This is the batch file and it's working fine for that purpose:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "folder=C:\AAA"
set "excludeFile=C:\BBB\CCC\list.txt"
set /p excludeName="Year not to delete: "
echo:
set /p rootPath="Backup folder path: "
FOR /f %%a in ('WMIC OS GET LocalDateTime ^| find "."') DO Set _DTS=%%a
Set _date=%_DTS:~0,4%%_DTS:~4,2%%_DTS:~6,2%
if "%rootPath:~-1%"=="\" (set rootPath= %rootPath:~0,-1%)
set localPath=%rootPath%\backup_deleted_media_%_date%
echo:
rem // Change to the root directory:
pushd "%folder%" && (
rem // Loop through all files but exclude those listed in the list file:
for /F "delims= eol=|" %%F in ('
dir /B /S /A:-D "*.*" ^| findstr /V /L /I /X /G:"%excludeFile%"') do (
for /D %%I in ("%%F\..") do (
echo.%%~nxI|findstr /C:"%excludeFile%" >nul 2>&1
if not errorlevel 1 (
echo Found
) else (
if not exist %localPath%\%%~pF md %localPath%\%%~pF
move %%F %localPath%\%%~pF
)
)
)
)
rem // Return from currently iterated directory to root directory:
endlocal
cmd /k
What I need now is another batch file for doing more or less the same but:
folderis notC:\AAA, but isC:\EEE\AAA- I have to change the path of the files in
list.txtreplacingC:\AAAbyC:\EEE\AAAand I have to add.jpgto every single row of thatlist.txt(because, by mistake, all the files inC:\EEE\AAAand its subfolders have that extension, so likeimage_1.jpg.jpg,pdf_1.pdf.jpg, ...) before doing the same move. And I want these changes to be in a new file (%newExcludeFile%) instead of the originallist.txt.
So I've added:
set "newExcludeFile=C:\BBB\CCC\list_new.txt"
set "SEARCHTEXT=\AAA\"
set "REPLACETEXT=\EEE\AAA\"
and I was doing this for deleting and creating the file %newExcludeFile% from the file %excludeFile%
if exist "%newExcludeFile%" del "%newExcludeFile%"
call jrepl "%SEARCHTEXT%" "%REPLACETEXT%" /x /m /l /f "%excludeFile%" /o "%newExcludeFile%"
Now I'm missing the part for appending .jpg at the end of every record in the file %newExcludeFile% and I was thinking if there is a way for doing it without iterating all the rows again after that replace.
I recommend reading first the Stack Overflow page with the question:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
I post next the simple solution for the task to create the output file
C:\BBB\CCC\list_new.txtfrom input fileC:\BBB\CCC\list.txtwith replacingC:\AAAat beginning of each line byC:\EEE\AAAand append additionally at end of each line.jpgso that the lines inC:\BBB\CCC\list.txtbecome in file
C:\BBB\CCC\list_new.txtThis task can be done with:
That's really all.
/Freads one line after the other from fileC:\BBB\CCC\list.txt.delims=\.tokens=2*, with the exception of looking on starting with end of line character in which case the entire line would be ignored, too.C:and for that reason the defaulteol=;can be kept in this use case. There is no line ignored because of end of line character as there is no line starting with a semicolon and so no first substring starting with;.AAAwhich is assigned to specified loop variableIaccording totokens=2.C:\AAA\on each line which is assigned without further line splitting according to*aftertokens=2to next but one loop variableJ.It would be also possible to use the FOR command line:
This variant copies drive letter and colon (first substring) from source to destination file.
I am a fan of JREPL.BAT, but this batch/JScript hybrid is not really necessary for this task.
However, here is the command line doing the same using
jrepl.batas the command line withfor /F.It runs a regular expression search for
\AAA\whereby each backslash must be escaped with one more backslash as the backslash is the escape character in a search regular expression and.*$for 0 or more characters up to end of the line(and)with replacing each found string with
\EEE(with backslash not escaped by JScript exception) and$1the found string to keep it and.jpgappended.Next I want to let all readers of this answer know what was not good coded in the few lines of the batch file posted in the question with the reasons.
It is recommended to modify
to
The arguments for command IF are specified in this case with 100% correct syntax for a string comparison as described extensively by my answer on Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files with
"%rootPath:~-1%";==;"\".It can be seen on debugging the batch file that Windows command processor corrects automatically
if "%rootPath:~-1%"=="\"with the missing spaces around==toif "%rootPath:~-1%" == "\"with spaces before executing the command IF. Therefore it is best to write the string comparison condition 100% correct in the batch file with spaces around==.The space right of
=is removed in argument string of command SET in improved command line asrootPathshould not be redefined with a space at beginning as described in detail by my answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line?The argument string of the two SET commands are additionally enclosed in
"to work also for paths containing an ampersand character as otherwise&in path would be interpreted as AND operator for an additional command to execute after command SET. See my answer on single line with multiple commands using Windows batch file for meaning of&which is not within a double quoted argument string.See also my answer on syntax error in one of two almost-identical batch scripts: ")" cannot be processed syntactically here which describes several very common syntax issues. Issue 1 is not enclosing file/folder argument strings in double quotes as required on file/folder argument string containing a space or one of these characters
&()[]{}^=;!'+,`~as described by help of Windows command processor output on runningcmd /?in a command prompt window.The two command lines
are also very problematic if
localPathis for example defined with the stringC:\Temp\Test & Development.The command IF is designed to run one command on condition being true. There should not be used
(and)if just a single command needs to be executed on true condition although it is always possible to define a command block with just one command. This is the second common syntax issue on batch file coding.There are lots of characters in the ASCII table which have no special meaning for neither
cmd.exeprocessing a batch file and nor for its internal command FOR, but beginners in batch file writing tend towards using characters from the small set as loop variable which have a special meaning likeaorFwhich must be used very carefully on being used as loop variables.The command
popdshould be used always after a successful execution ofpushd, especially ifpushdassigns a network resource access with a UNC path to a drive letter. Otherwise it could happen on repeated execution of a batch file that all drive letters are used finally.It is very good practice to use the fully qualified file name of an executable wherever possible to make a batch file independent on the environment variables
PATHandPATHEXTand avoid unnecessary file system accesses by Windows command processor to find the files which are usually specified only with its file name likefindorfindstrorwmic.Here is the batch file code as posted in question with all more or less small issues fixed:
There is additionally corrected
/C:"%excludeFile%"to/C:"%excludeName%"in most inner FOR loop.Note: This batch file was not tested by me as I have never executed it!