Loop Through Files - Use Directory Name - batch-file

TL;DR: I want to be able to loop through each file in a folder / subfolders and use the directory name the file is in, in each loop.
If I had a directory structure like:
-- Main
----- Printer 1
------- File 1
------- File 2
----- Printer 2
------- File 1
Ideally what I need to do is loop through 'Main' and get the files in 'Printer 1' and 'Printer 2', but I need to use the name of the printer directories in the script. Eg:
At the moment I'm using the below:
:loop
for /f %%f in ('dir /b D:\FireflyWebApps\www\apps\label\resources\labels_to_print\') do (
"C:/Program Files/Java/jre1.8.0_66/bin/java" -jar C:\test\pdfbox.jar PrintPDF -silentPrint D:\FireflyWebApps\www\apps\label\resources\labels_to_print\%%f
del D:\FireflyWebApps\www\apps\label\resources\labels_to_print\%%f
)
ping localhost -n 5 > nul
goto loop
Which works well, it loops trough the directory and prints the PDF's, but I need this to work with multiple printers. I know it's not an ideal solution, but I need to change the default printer to the 'Printer X' file names ( so I'll store the printer name as the folder, then run the change default printer command using it ).
How can I use the folder name the file is in, in the batch script?
Possible Solution
The below script will cd to the directory, loop through the directories in it, performing the inner loop on each one. Before it runs the inner loop, it gets the directory name and sets the default printer. I had to do an IF == 1 as it's a printer and I can't use '\' in folder name.
cd C:\test
for /D %%d in (*) do (
IF "%%d" == "1" (
RUNDLL32 PRINTUI.DLL,PrintUIEntry /y /n "\\192.168.102.131\lp1"
)
for /f %%f in ('dir /b C:\test\%%d') do (
echo %%f
)
)
pause

Here is my solution to your problem of getting folder name of a file:
#echo off
setlocal EnableDelayedExpansion
:loop
for /F "delims=" %%F in ('dir /A-D /B /S "D:\FireflyWebApps\www\apps\label\resources\labels_to_print\*" 2^>nul') do (
set "FolderPath=%%~dpF"
set "FolderPath=!FolderPath:~0,-1!"
for %%P in ("!FolderPath!") do (
echo Printer name is: %%~nxP
"%ProgramFiles%\Java\jre1.8.0_66\bin\java.exe" -jar C:\test\pdfbox.jar PrintPDF -silentPrint "%%F"
del "%%F"
)
)
ping localhost -n 5 > nul
goto loop
Command DIR with the options /A-D /B /S returns a list of all file names with full path without double quotes from specified directory and all subdirectories.
Drive and path with a backslash at end is assigned to an environment variable. The backslash at end must be removed which is done with a string substitution copying folder path string with exception of last character.
This folder path now without backslash at end is used in a second FOR loop which of course has always only 1 loop run to get with %%~nxP the name of the folder in which current file is stored which is the printer name.
The batch file as is just outputs the printer name.
Delayed variable expansion must be used here because of FolderPath being defined within a block.
Command DIR outputs an error message if it can't find any file in any directory. This error message is redirected from stderr to nul as of no interest for this batch file running continuously.
An alternate method without using command DIR working also for Unicode file names (© Joey):
#echo off
setlocal EnableDelayedExpansion
:loop
for /R "D:\FireflyWebApps\www\apps\label\resources\labels_to_print" %%F in (*) do (
set "FolderPath=%%~dpF"
set "FolderPath=!FolderPath:~0,-1!"
for %%P in ("!FolderPath!") do (
echo Printer name is: %%~nxP
"%ProgramFiles%\Java\jre1.8.0_66\bin\java.exe" -jar C:\test\pdfbox.jar PrintPDF -silentPrint "%%F"
del "%%F"
)
)
ping localhost -n 5 > nul
goto loop
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.
dir /?
echo /?
for /?
goto /?
ping /?
set /?
setlocal /?

Related

Can I use FOR /L counter variable in the FOR command?

::for /l %%n in (0, 1, 6) do (
for /F "skip=1 delims=" %%i in (path.txt) do set "dirvar=%%i"&goto nextline
:nextline
for /F "skip=1 delims=" %%i in (file.txt) do set "filevar=%%i"&goto nextline
:nextline
for /F "skip=1 delims=" %%i in (dotonefile.txt) do set "dotvar=%%i"&goto nextline
:nextline
SET dirvar=%dirvar%
SET filevar=%filevar%
SET dotvar=%dotvar%
SET dirfile=%dirvar%%filevar%
SET dirdotfile=%dirvar%%dotvar%
IF EXIST %dirfile% (
del %dirdotfile%
) ELSE (
rename %dirdotfile% %dirfile%
)
::)
My batch script above works fine in that it runs one time. It reads the 2nd line from three separate text files into variables. Then it tests to see if a filename is in a directory and if it is named IMG001.jpg it deletes IMG001.1.jpg. in the same directory. If IMG001.jpg is NOT found in the directory, it renames IMG001.1.jpg in the directory to IMG001.jpg.
path.txt is just a text file with a list of folder paths like:
F:\My Pictures\2005-Misc\
F:\My Pictures\2006-Misc\
F:\My Pictures\2007-Misc\
file.txt is just a text file with a list file names, where line 1 is a file in the directory that's also line 1 of the path.txt file. So there could be a IMG001.jpg in the 2005-Misc folder, could be a IMG001.jpg in the 2006-Misc folder, and there could be a IMG001.jpg in the 2007-Misc folder:
IMG001.JPG
IMG001.JPG
IMG001.JPG
Similarly with dotonefile.txt, it's a list of filenames that ARE in the corresponding directory listed in path.txt. So there IS a IMG001.1.jpg in folder 2005-Misc, there's one in 2006-Misc, and there's one in 2007-Misc.
IMG001.1.JPG
IMG001.1.JPG
IMG001.1.JPG
I want to loop this script and repeat it so it reads in lines 1 through n (n can be hard coded, above it is currently 7) from the text files to variables, then tests and renames for each filename.
I tried uncommenting the first and last lines and then in the three for loops, I replaced the hardcoded "1" with "%%n" but the batch file won't run erroring with "the sntax of the command is incorrect". Below is my attempt that doesn't work. Any advice on how to tweak it to run? I've tried all kinds of combinations of making a new count variable that increments by 1 at the end, using delayed expansion in various forms of variables, nothing works.
for /l %%n in (0, 1, 6) do (
for /F "skip=%%n delims=" %%i in (path.txt) do set "dirvar=%%i"&goto nextline
:nextline
for /F "skip=%%n delims=" %%i in (file.txt) do set "filevar=%%i"&goto nextline
:nextline
for /F "skip=%%n delims=" %%i in (dotonefile.txt) do set "dotvar=%%i"&goto nextline
:nextline
SET dirvar=%dirvar%
SET filevar=%filevar%
SET dotvar=%dotvar%
SET dirfile=%dirvar%%filevar%
SET dirdotfile=%dirvar%%dotvar%
IF EXIST %dirfile% (
del %dirdotfile%
) ELSE (
rename %dirdotfile% %dirfile%
)
)
The main problem is that Windows command processor cmd.exe does not support labels inside command blocks which are parsed completely before executing the command making use of the command block. Please read for details How does the Windows Command Interpreter (CMD.EXE) parse scripts?
The solutions is using a subroutine.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /L %%N in (0,1,6) do call :ProcessFiles %%N
endlocal
goto :EOF
:ProcessFiles
if not %1 == 0 ( set "SkipOption=skip=%1 " ) else ( set "SkipOption=" )
set "DirVar="
for /F "%SkipOption%eol=| delims=" %%I in (path.txt) do set "DirVar=%%I" & goto GetFileVar
:GetFileVar
set "FileVar="
for /F "%SkipOption%eol=| delims=" %%I in (file.txt) do set "FileVar=%%I" & goto GetDotVar
:GetDotVar
set "DotVar="
for /F "%SkipOption%eol=| delims=" %%I in (dotonefile.txt) do set "DotVar=%%I" & goto CheckFile
:CheckFile
set "DirFile=%DirVar%%FileVar%"
set "DirDotFile=%DirVar%%DotVar%"
if exist "%DirFile%" (
del "%DirDotFile%"
) else (
rename "%DirDotFile%" "%DirFile%"
)
goto :EOF
A smarter approach would be using this batch file code without usage of text files at all.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir "F:\My Pictures\*.1.JPG" /A-D /B /S 2^>nul') do (
for %%J in ("%%~dpnI") do (
if exist "%%~dpnJ%%~xI" (
del "%%I"
) else (
ren "%%I" "%%~nJ%%~xI"
)
)
)
endlocal
The FOR loop starts with %ComSpec% /C one more cmd.exe command process in background to execute the command line:
dir "F:\My Pictures\*.1.JPG" /A-D /B /S 2>nul
DIR searches with the specified options for
files because of option /A-D (attribute not directory)
matching case-insensitive the pattern *.1.JPG
in directory F:\My Pictures and all its subdirectories because of option /S
and outputs in bare format because of option /B just
file name with file extension and with full path because of option /S.
DIR would output an error message in case of no file can be found in entire directory tree matching these criteria. This error message is suppressed by redirecting it to device NUL.
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.
FOR captures everything output to handle STDOUT of started command process and processes the captured text line by line after started cmd.exe finished.
FOR ignores empty lines which do not occur here at all. FOR would also ignore lines starting with ; because of being the default for end of line option. As DIR outputs the file names with full path, it is not possible that a line starts with ;. But eol=| is nevertheless used to define the vertical bar as end of line which no folder/file name can contain ever.
FOR splits up by default each line into substrings (tokens) using normal space and horizontal tab character as delimiters. This behavior is not wanted here as file path could contain a space character. For that reason delims= is used to define an empty list of delimiters which disables the line splitting behavior.
The inner FOR is used to get assigned to loop variable J just the string left to .1.JPG.
The IF condition checks if there is already a file *.JPG for current file *.1.JPG in same directory as current file in which case the file *.1.JPG is deleted or otherwise the renamed to *.JPG if this file deletion or file rename operation is permitted at all depending on read-only attribute, file permissions of current account and current file sharing access permissions.
But let us assume the image file names can be any file name matching *.jpg and there can be not only *.1.jpg, but also *.2.jpg to *.99.jpg image files, i.e. any number after a dot before file extension .jpg. In this case DIR is not enough to get the list of file names with file extension and full path. It is additionally necessary to use FINDSTR with a regular expression to filter the list of file names.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir "F:\My Pictures\*.*.jpg" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R "\.[0123456789][0123456789]*\.jpg$"') do (
for %%J in ("%%~dpnI") do (
if exist "%%~dpnJ%%~xI" (
del "%%I"
) else (
ren "%%I" "%%~nJ%%~xI"
)
)
)
endlocal
First FINDSTR outputs just lines read from STDIN which
matches case-sensitive because of option /I
the regular expression \.[0123456789][0123456789]*\.jpg$
as explicitly declared with option /R.
The regular expression matches a string consisting of a dot, one or more digits, one more dot and the string jpg found at end of line. So a file name like Hello.World.jpg output by DIR is not matched by FINDSTR and therefore not output by FINDSTR and so not processed by FOR.
But a file name like Hello.World.393.jpg is processed and either deleted or renamed to Hello.World.jpg depending on existence of Hello.World.jpg in same directory.
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 /?
findstr /?
for /?
goto /?
if /?
ren /? or rename /?
set /?
setlocal /?
See also Where does GOTO :EOF return to?

How to move files with a keyword with a lookup file using a batch file?

I have a list of IDs in a CSV file stored in a folder. Then I have files which contains these IDs. I want to move the files if it is present in the CSV file.
For example:
I have this documents in Docs folder: Jose_1234_CV.pdf, Jose_111_CV.doc, Jose_2323_CV.doc
I have IDs.csv file containing the following IDs: 1234, 111
When I run the batch job, the files with the IDs 1234 and 111 should be moved to a particular folder.
I have the below code working only if in the look up file contains the exact file name. I want it work even if it only find the ID:
#echo off
set "Source=C:\users\directory"
set "Target=C:\users\target"
set "FileList=C:\users\lookup\ID.csv"
echo/
if not exist "%Source%" echo Source folder "%Source%" not found & goto :Quit
if not exist "%FileList%" echo File list "%FileList%" not found & goto :Quit
2> nul md "%Target%"
for /F usebackq^ delims^=^ eol^= %%a in ("%FileList%") do (
for /F "delims=" %%b in ('dir /B /S /A:-D "%Source%\%%a"') do (
move "%%b" "%Target%"
)
)
:Quit
echo/
echo Press the Space bar to close this window.
pause > nul
This could be done with following batch file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BaseDirectory=C:\Users"
set "Source=%BaseDirectory%\directory"
set "Target=%BaseDirectory%\target"
set "FileList=%BaseDirectory%\lookup\IDs.csv"
set "TempFile=%TEMP%\%~n0.tmp"
if not exist "%Source%\" echo Source folder "%Source%" not found. & goto Quit
if not exist "%Source%\*_*_CV.*" echo Folder "%Source%" does not contain any *_*_CV.* file. & goto Quit
if not exist "%FileList%" echo File list "%FileList%" not found. & goto Quit
md "%Target%" 2>nul
if not exist "%Target%\" echo Folder "%Target%" could not be created. & goto Quit
set "FileMoved=0"
del "%TempFile%" 2>nul
rem Create a copy of list file with each identifer surrounded by underscores
rem to make sure that on an identifier like 111 just the file with _111_ in
rem name and not with _2111_ or _1114_ in name is moved to target folder.
for /F "usebackq delims=" %%I in ("%FileList%") do echo _%%~I_>>"%TempFile%"
rem Move all files containing one of the identifiers in
rem temporary file in its file name to the target folder.
for /F "eol=| delims=" %%I in ('dir "%Source%\*_*_CV.*" /A-D-H /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /G:"%TempFile%" 2^>nul') do (
move /Y "%%I" "%Target%\%%~nxI" >nul
if not errorlevel 1 set /A FileMoved+=1
)
rem Delete the temporary file no longer needed.
del "%TempFile%"
rem Delete the target directory if being empty.
if %FileMoved% == 0 rd "%Target%" 2>nul
rem Inform user about number of moved files.
set "Plural_S=s"
if %FileMoved% == 1 set "Plural_S="
echo Moved %FileMoved% *.csv file%Plural_S% to "%Target%".
:Quit
endlocal
echo/
echo Press SPACE to close this window.
pause >nul
This batch code expects that the file C:\Users\lookup\IDs.csv contains the identifiers line by line like:
1234
111
The first FOR command creates a copy of IDs.csv with the lines:
_1234_
_111_
The second FOR executes in a separate command process started with cmd.exe /C in background (= not visible) the command line:
dir "C:\Users\directory\*_*_CV.*" /A-D-H /B /S 2>nul | C:\Windows\System32\findstr.exe /L /G:"C:\Users\UserName\AppData\Local\Temp\BatchFileName.tmp" 2>nul
So the command process in background with no console window is first running command DIR which outputs
all non hidden files because of /A-D-H (attribute not directory and not hidden)
matching the wildcard pattern *_*_CV.*
in bare format because of /B which means file name only
in specified directory and all its subdirectories because of /S
with full path also because of /S
to handle STDOUT.
DIR outputs an error message if it can't find any file matching the wildcard pattern. This error message written to handle STDERR is suppressed by redirecting it to device NUL with 2>nul.
The file names with full path output by DIR line by line to handle STDOUT are redirected with | to handle STDIN of next command FINDSTR.
FINDSTR searches in the list of file names for
any string listed in temporary file specified after /G:
case-sensitive because of not using /I
and literally because of using /L
and outputs the lines (= file names with full path) containing one of the strings in the temporary file.
That means no directory in path of a file should contain _ID_ or otherwise files are moved which do not contain the identifier in file name, but in its path.
It is possible that FINDSTR can't find any line matching the search criteria and therefore outputs an error message to handle STDERR which is suppressed by redirecting it with 2>nul to device NUL.
The command FOR captures the output written to handle STDOUT of the background command process which is the output of DIR filtered with FINDSTR and then processes this output line by line.
Empty lines are ignored by FOR. But that does not matter here as the list of file names each with full path does not contain empty lines.
Lines starting with a semicolon would be also ignored by FOR, but this behavior is modified with eol=| to ignore just lines starting with a vertical bar. A vertical bar is impossible here as no directory or file can contain a vertical bar in name. Well, it is also practically impossible that a file name with full path starts with a semicolon. So eol=| would not be really needed here.
FOR with parameter /F splits by default a line up into substrings using space and horizontal tab as string delimiters and assign only the first space/tab delimited string to specified loop variable I. This split behavior is not wanted here as needed in body command block of FOR is always the full qualified name of a file to move even on path or file name contains a space character. For that reason delims= is specified to define an empty list of delimiters which disables splitting up the lines into substrings.
MOVE is executed which moves the file and exits with 0 on success and with any value greater 0 on an error.
The exit code of an executed application or command is assigned by Windows command interpreter to environment variable ERRORLEVEL.
The IF condition checks if MOVE exited not with a value greater or equal 1, i.e. with 0 (or a negative value) for success. In this case file was moved successfully and the appropriate counter is increased by one.
If the source directory contains never subdirectories, it would be better to use for second FOR loop:
for /F "eol=| delims=" %%I in ('dir "%Source%\*_*_CV.*" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /G:"%TempFile%" 2^>nul') do (
move /Y "%Source%\%%I" "%Target%\%%I" >nul
if not errorlevel 1 set /A FileMoved+=1
)
DIR is here without /S and so output are the non hidden files matching the wildcard pattern without path. For that reason FINDSTR searches in file name only for _ID_. The command MOVE must contain %Source%\ as %%I is in this case just the name of a file without path.
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.
del /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
md /?
move /?
pause /?
rd /?
rem /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | 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 command line with using a separate command process started in background.

Batch - delete all folders in a folder except those listed in a text file

The aim is to delete all folders (and their sub-folders) except those folders whose names are listed in a text file.
The text file is "F:\Documents\Batch\my folders.txt" and the content is
ABC
DEF
The folders to be deleted are in "F:\Documents\Batch\Practice folder". It has the following folders in it: ABC, DEF, GHI and JKL.
After running my batch file, only ABC and DEF should remain and all other folder (GHI, JKL) should be deleted
Here is what I've tried:
#echo off
set WORKDIR="F:\Documents\Batch\Practice folder"
set LISTFILES="F:\Documents\Batch\my folders.txt"
pushd %WORKDIR%
for /d %%G in (*) do (
for /f "tokens=* usebackq" %%H in (%LISTFILES%) do (
if %%G==%%H rd /s /q "%%G"
)
)
popd
Please help me find a more effective and/or shorter way to do this.
EDIT 1:
That code deletes all the folders that match the names in the LISTFILES. But when I do any of:
if not %%G==%%H rd /s /q "%%G"
if not [%%G]==[%%H] rd /s /q "%%G"
if not "%%G"=="%%H" rd /s /q "%%G"
with or without /i (i.e. if /i), all folders are delete regardless.
So, I tried this and it work
#echo off
setlocal enableDelayedExpansion
set WORKDIR="D:\IFX\services\4"
set LISTFILES="D:\IFX\services\files.txt"
set delete=
pushd %WORKDIR%
for /d %%G in (*) do (
set delete=1
for /f "tokens=* usebackq" %%H in (%LISTFILES%) do (
if /i %%G equ %%H set delete=0
)
if !delete!==1 rd /s /q %%G
)
popd
for /d %%G in (*) do as posted in question processes each non hidden subdirectory in current directory whereby loop variable G contains on each loop run the name of a subdirectory without path. Subdirectories with hidden attribute set are ignored by FOR.
And because of enabled delayed environment variable expansion the FOR loop in question does not work for directory names containing one or more exclamation marks. %%G is expanded to current directory name and when this name contains !, the exclamation mark is interpreted as begin or end of an environment variable name. So everything between two exclamation marks is replaced by current value of the environment variable with name being the string between the two exclamation marks, or more likely with nothing in case of no environment variable exists with that name. A single (remaining) exclamation mark is removed from the directory name. After this additional preprocessing caused by enabled delayed expansion, the (remaining) directory name is really processed further by the appropriate command like IF and RD fails to delete the manipulated directory or deletes the wrong directory.
A batch file for this task working also for hidden subdirectories and directories with one or more exclamation mark in name is:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "WORKDIR=F:\Documents\Batch\Practice folder"
set "LISTFILE=F:\Documents\Batch\my folders.txt"
for /F "eol=| delims=" %%I in ('dir "%WORKDIR%\*" /AD /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /G:"%LISTFILE%"') do rd /Q /S "%WORKDIR%\%%I"
endlocal
This batch file can be optimized to a single line too.
#for /F "eol=| delims=" %%I in ('dir "F:\Documents\Batch\Practice folder\*" /AD /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /G:"F:\Documents\Batch\my folders.txt"') do #rd /Q /S "F:\Documents\Batch\Practice folder\%%I"
dir "F:\Documents\Batch\Practice folder\*" /AD /B outputs to handle STDOUT because of /AD (attribute directory) the list of subdirectories in directory F:\Documents\Batch\Practice folder in bare format because of /B which means just directory name without path. DIR outputs with these options also subdirectories with hidden attribute set.
For the given example the output list is:
ABC
DEF
GHI
JKL
DIR outputs an error message to handle STDERR if it can't find any subdirectory in specified directory or the specified directory does not exist at all that it can't find the specified file instead of directory. This possible and misleading error message is suppressed by redirecting it with 2>nul to device NUL.
The list of subdirectories output by DIR to STDOUT is redirected with | to handle STDIN of next command FINDSTR.
FINDSTR searches in the list of subdirectories read from STDIN
case-insensitive because of /I
literally because of /L
for entire lines because of /X
for any string listed in file specified with /G:"..."
and outputs to STDOUT all lines NOT matching any search string in list file because of /V (inVerted result).
The output of FINDSTR for the given example is:
GHI
JKL
The entire command line with DIR and FINDSTR is executed by FOR in a background command process started with cmd.exe /C. FOR captures everything output in this command process to STDOUT and processes it next line by line.
The redirection operators | and > must be escaped here with caret character ^ to be interpreted first as literal characters when Windows command interpreter parses the entire FOR command line. Otherwise Windows command interpreter would exit batch processing on FOR command line because of misplaced redirection operators for command FOR.
So FOR finally executes in background without displaying a window:
cmd.exe /C dir "F:\Documents\Batch\Practice folder\*" /AD /B 2>nul | C:\Windows\System32\findstr.exe /I /L /V /X /G:"F:\Documents\Batch\my folders.txt"
The loop variable I contains on each loop run a directory name without path found in F:\Documents\Batch\Practice folder and not listed in list file F:\Documents\Batch\my folders.txt. The executed command RD deletes quietly (/Q) this directory with all its subdirectories (/S).
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.
dir /?
echo /?
endlocal /?
findstr /?
for /?
rd /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators. And the answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? explains why it is recommended to use set "variable=value" instead of set variable="value" because the position of first " makes a big difference in interpretation by Windows command interpreter.

Forfiles with 7z zip ONLY last modified file

I am trying to zip only last modified file from a folder to help my workflow with bat file
but its giving an error
ERROR: No files found with the specified search criteria.
Here is my complete code
#ECHO ON
SET "SourceDir=C:\Users\user1\Documents\Work"
SET "ZipName=testing.zip"
SET "DestDir=C:\Users\user1\Documents\Work\result"
SET "now=%date:~4%"
CD /D "%DestDir%"
FORFILES /D %now% /m *.csv /c "cmd /c 7z.exe a -aoa -tzip %ZipName% %SourceDir% "
I am pretty sure there is file last modified today. I assume its didn't recognise the sourcedir? Am I missing in the quote?
I suggest not using command FORFILES, but use instead the commands FOR and DIR.
#echo off
set "SourceDir=%USERPROFILE%\Documents\Work"
set "ZipName=testing.zip"
set "DestDir=%USERPROFILE%\Documents\Work\result"
for /F "delims=" %%I in ('dir "%SourceDir%\*" /A-D /B /O-D 2^>nul') do 7z.exe a -aoa -tzip "%DestDir%\%ZipName%" "%SourceDir%\%%I" & goto Done
:Done
DIR searches in specified source directory with wildcard pattern * because of /A-D (attribute not directory) only for files and outputs them because of /B (bare format) with file name only ordered by last modification date in reverse order because of /O-D which means newest file is output first.
FOR process this output by DIR line by line. For the first line 7z.exe is called to compress the file into the ZIP archive file.
Then goto :Done is executed to exit the FOR loop as all other files found and output by DIR are of no interest.
I suggest to specify 7z.exe with full path in the batch file.
2^>nul redirects the error message output by DIR if no file is found in source directory to device NUL to suppress it. The redirection operator > must be escaped here with caret character ^ to be interpreted as literal character on Windows command interpreter parses the entire FOR command line. The escape character ^ is already removed later on execution of DIR command line in a separate command process opened by FOR in background.
Another version processing only files with archive attribute set and clear the archive attribute for each file compressed into the ZIP archive file.
#echo off
set "SourceDir=%USERPROFILE%\Documents\Work"
set "ZipName=testing.zip"
set "DestDir=%USERPROFILE%\Documents\Work\result"
for /F "delims=" %%I in ('dir "%SourceDir%\*" /AA-D /B 2^>nul') do (
7z.exe a -aoa -tzip "%DestDir%\%ZipName%" "%SourceDir%\%%I"
%SystemRoot%\System32\attrib.exe -a "%SourceDir%\%%I"
)
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.
attrib /?
dir /?
echo /?
for /?
goto /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.

Folder Monitoring with Batch File

I want to monitor my folder if new file added or not. Then If added I would like to execute some files. But I don't want to use third party app.
I have some ideas but I don't know how to do that.
This is my folder; D:\MonitoringFolder
So every hour batch file will check the files inside of it and writes them into a txt.
dir /b "D:\MonitoringFolder" > old.txt
Old.txt is --> string 1 , string 2, string 3
After one hour, batch file will check it later and writes again into another txt.
dir /b "D:\MonitoringFolder" > new.txt
New.txt is --> string 1, string 2, string 3, string 5
Then it will compare new.txt and old.txt. So string 5 added recently. It will prompt a window and says "String 5" added!. Or new file added (removed).
I want to do that If someone could show me a way to do this I would appreciate that.
Script MONITOR.cmd scheduled to run every now and then:
IF EXIST NEW.TXT DEL NEW.TXT
FOR /F "tokens=*" %%* IN ('DIR /S /B /ON "D:\MonitoringFolder"') DO ECHO "%%*">>NEW.TXT
FOR /F "tokens=*" %%* IN (NEW.TXT) DO (FIND %%* OLD.TXT >NUL || START CMD /K INSERTED.cmd %%*)
FOR /F "tokens=*" %%* IN (OLD.TXT) DO (FIND %%* NEW.TXT >NUL || START CMD /K DELETED.cmd %%*)
DEL OLD.TXT
REN NEW.TXT OLD.TXT
Script INSERTED.cmd will create new window prompting for action on appearing of a new file:
ECHO Inserted new file %1
DIR %1
PAUSE & EXIT
Script DELETED.cmd will create new window prompting for action on disappearing of an old file:
ECHO Deleted file %1
PAUSE & EXIT
Subfolders are monitored, too. It worked for me even with spaces and accented characters in filename.
Since you're already dumping the output every hour, just execute this command from the prompt:
fc /u old.txt new.txt
It will tell you, if any, which differences exist between the two files.
Maybe you're going to write batch scripts (for scanning folder and compare results) and schedule them with a scheduler like cron (Linux) or windows task scheduler every hours for e periodical checking. Some documents here : http://support.microsoft.com/kb/308569 , http://code.tutsplus.com/tutorials/scheduling-tasks-with-cron-jobs--net-8800
#ECHO OFF &SETLOCAL disableDelayedExpansion
SET "SaveFile=Save.File"
IF NOT EXIST "%SaveFile%" GOTO:cont
DIR /b /a-d | FINDSTR /vg:"%SaveFile%">nul||EXIT /b
ECHO(execute some programs here
:cont
>"%SaveFile%" DIR /b /a-d

Resources