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.
Related
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.
I have a batch script already working for some months. The purpose of the script is to create a folder based on the file name and rename the folder accordingly for a certain purpose. However, it stops moving the files to the created folder in the loop. I tested it on other machine and it was working fine, but on a particular machine; it is just not working.
What can I do to make the loop effective and why did the batch stop working (moving files to folder) after working for many months now?
setlocal EnableDelayedExpansion
for /F %%a in ('dir "C:\Program Files\WinSCP\Unconverted" /a-d /b') do (
if not "%%~dpnxa"=="%~dpnx0" call :func "%%~a"
:func
set file=%~1
set dir=%file:~0,49%
mkdir "C:\Program Files\WinSCP\Unconverted\%dir%_fdc" 2>nul
rem ECHO "%file%"
rem ECHO "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
move /Y "C:\Program Files\WinSCP\Unconverted\%file%" "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
)
start "" "C:\Program Files\WinSCP\hide_conversion_window.exe"
I rewrote and commented the batch file as it contains several issues whereby most were not problematic as long as this batch file is stored in %ProgramFiles%\WinSCP\Unconverted and this directory is also the current directory on execution of the batch file as on double clicking the batch file.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=%ProgramFiles%\WinSCP\Unconverted"
rem Process all files in source folder found by command DIR with ignoring
rem subfolders and listed in bare format which means only file names with
rem file extension but without file path. The batch file itself is skipped
rem if being also stored in the source folder specified above.
for /F "delims=" %%I in ('dir "%SourceFolder%\*" /A-D /B 2^>nul') do (
if /I not "%SourceFolder%\%%I"=="%~f0" call :MoveFile "%SourceFolder%\%%I"
)
rem Execute converter through AutoIt in a separate command process and
rem while conversion is running continue with batch processing which means
rem restoring previous environment and finally exiting batch file processing.
start "" "%ProgramFiles%\WinSCP\hide_conversion_window.exe"
endlocal
goto :EOF
rem MoveFile is a subroutine which expects to be called with one argument
rem being the name of the file to move with full file name which means
rem with file path, file name and file extension.
rem The first 49 characters of the file name define the name for target
rem folder on which "_fdc" must be appended for completion. This folder
rem is created without verification on success and then the file is
rem moved into this folder again without verification on success.
:MoveFile
set "FileName=%~nx1"
set "FolderName=%FileName:~0,49%_fdc"
mkdir "%~dp1\%FolderName%" 2>nul
move /Y "%~1" "%~dp1\%FolderName%\" >nul
goto :EOF
This batch file works for batch file being stored in a different folder than source folder or current directory is a different directory than the folder containing the batch file or a found file contains a space character or any other special character like &()[]{}^=;!'+,`~.
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 /?
echo /?
endlocal /?
for /?
goto /?
if /?
mkdir /?
move /?
set /?
setlocal /?
start /?
Read also the Microsoft article about Using Command Redirection Operators.
Thanks for the suggestion oldabi. Sometimes things do work and we are thinking is all perfect until it breaks down. Thanks for the suggestion. I just realised my mistake about missing bracket.
SETLOCAL ENABLEDELAYEDEXPANSION
for /F %%a in ('dir "C:\Program Files\WinSCP\Unconverted" /a-d /b') do (
if not "%%~dpnxa"=="%~dpnx0" call :func "%%~a" )
goto conversion
:conversion
rem ::execute converter through autoit
start "" "C:\Program Files\WinSCP\hide_conversion_window.exe"
:func
set file=%~1
set dir=%file:~0,49%
mkdir "C:\Program Files\WinSCP\Unconverted\%dir%_fdc" 2>nul
rem ECHO "%file%"
rem ECHO "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
MOVE /Y "C:\Program Files\WinSCP\Unconverted\%file%" "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
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.
I have a directory F:\Input with various subfolders in it.
I need to specifically copy only those folders which has same naming convention such as India012345.zip, India09876.zip, etc. These are really folders with unusual .zip in folder name and not ZIP files!
I need to copy those folders along with their contents (subfolders and files) to a different location.
CD /D F:\Input\
FOR /f "tokens=*" %%I in ('dir /s /b /a:d "India*"') do echo|xcopy "%%I" "E:\output\" /s
This is my present code which copies the contents but not the main folders India012345.zip.
Folder structure of F:\Input:
Country
state
0021
op 1
qwerty
India09876.zip (folder, not compressed)
31-Jun-2016
XML and PDF files
vcxz
03-Aug-2016.zip (file, compressed)
0031
op 1
India1234.zip (folder, not compressed)
31-Jun-2016
XML and PDF files
vcxz
04-Aug-2016.zip (file, compressed)
India*.zip will be unique in terms of nos.
It is not possible to rename. Please provide solution to copy as follows:
Folder E:\Output should contain after batch execution:
India09876.zip
31-Jun-2016
XML and PDF files
vcxz
03-Aug-2016.zip
India1234.zip
31-Jun-2016
XML and PDF files
vcxz
04-Aug-2016.zip
The India*.zip directory name must be also specified in destination path and some more options of command XCOPY should be used like /I to automatically create the destination folder, too.
#echo off
for /F "delims=" %%I in ('dir "F:\Input\India*.zip" /A:D /B /S 2^>nul') do xcopy "%%I" "E:\Output\%%~nxI\" /C /H /I /K /Q /R /S /Y >nul
It would be very easy possible to remove unusual .zip from the folder names during the copying process by using:
#echo off
for /F "delims=" %%I in ('dir "F:\Input\India*.zip" /A:D /B /S 2^>nul') do xcopy "%%I" "E:\Output\%%~nI\" /C /H /I /K /Q /R /S /Y >nul
%%~nI is used instead of %%~nxI to get rid of "file extension" from folder name.
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 /?
xcopy /?
And read also the Microsoft article about Using command redirection operators for an explanation of >nul.
2^>nul is 2>nul with redirection operator > escaped with ^ to apply 2>nul on execution of command DIR instead of interpreting the redirection on parsing the FOR command line which would result in an exit of batch processing because of a syntax error.
2>nul used on execution of DIR results in redirecting a possible error message output by DIR to STDERR to device NUL to suppress it. Command DIR outputs the confusing error message File not found to standard error stream if it can't find any folder matching the folder name wildcard pattern India*.zip.
I'm trying to write a command script (.cmd file) that will find the newest file and rename its extension.
So if there is:
file1.txt
file2.txt
file3.txt
And file3.txt is the newest, the script should change the extension to .xml, so the end result will be file3.xml.
If I do the following it will rename the file's extension:
move file3.txt file3.xml
But I don't know how to find the newest file, and then change its extension.
You could use following batch code:
#echo off
for /F "eol=| delims=" %%F in ('dir /B /O-D /TW "C:\Temp\Test\*.txt" 2^>nul') do (
ren "C:\Temp\Test\%%F" "%%~nF.xml"
goto :EOF
)
The command DIR returns a list of file names matching pattern *.txt without path and without any other data because of /B (bare format) sorted reverse according to last modification date (newest first) because of /O-D /TW.
This list is processed line by line by command FOR which executes for first file name the rename command to change the file extension for newest *.txt file in the specified directory. The loop and the batch file processing is exited after renaming first file because of goto :EOF. EOF is a predefined label which means End Of File.
If the current directory on running the batch file is always the directory with the text files, the batch file could be coded also as:
#echo off
for /F "eol=| delims=" %%F in ('dir /B /O-D /TW *.txt 2^>nul') do (
ren "%%F" "%%~nF.xml"
goto :EOF
)
delims= turns off splitting the file name returned by command DIR into tokes by spaces in case of the newest file contains 1 or more spaces in file name.
2^>nul redirects any error message because of no *.txt file in current respectively specified directory to device nul to suppress this error message whereby the redirection operator > is escaped here with ^ because of using it within command FOR.
%%~nF means file name only without file extension and dot separating the file extension from file name.
For understanding the used commands even better and how they work here, 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 /?
ren /?