This question is related to Test IF file exist, ELSE xcopy these two files.
Background: On occasion I choose to run aGallery-dl.bat in a given folder (just one in each of 100's of folders). It first deletes Folder.jpg then renames Folder2.jpg to Folder.jpg. This has the effect of a red X being replaced by a yellow ! when viewing the folder with parent folder selected in File Explorer. Secondly, it calls gallery-dl.exe. I use going from red X to yellow ! to let me know I've run aGallery-dl.bat at least once. If aGallery-dl.bat completes successfully, it finally deletes the Folder.jpg (currently yellow !), and now the representative contents of the folder (usually DeviantArt .jpg's) are visible. All is well.
rem #echo off
del .\Folder.jpg
ren .\Folder2.jpg Folder.jpg
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
"C:\Program Files (x86)\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive ".\aGDB.sqlite3" "https://www.deviantart.com/"%FOLDER%"/gallery/all"
del .\Folder.jpg
Problem: Restating, Gallery-dl.bat is in each of 100's of folders. On occasion, I run one of these from within it's local folder. Line 5, if the call to the web site is successful, gallery-dl.exe creates zzzGDB.sqlite3 within the local folder.
In the previous code, when aGallery-dl.bat completed, it would just delete the Folder.jpg. This assumes the call to the web page was successful. On rare occasion, the call to the web page will fail for any number of reasons, though at close (due to that final del .\Folder.jpg), it will still delete folder.jpg.
If zzzGDB.sqlite3 was not created/not present, I need the Folder.jpg (yellow !) to remain.
So, in the below code (line 6, now blank), I've lopped off the final del .\Folder.jpg and am trying to plug-in the provided code beginning at line 7, inserting a test for zzzGDB.sqlite. If found, del .\Folder.jpg. If not found, no action is taken against folder.jpg (it remains).
(The rem statement at the very bottom is just acting as a placeholder for my own knowledge.)
rem #echo off
del .\Folder.jpg
ren .\Folder2.jpg Folder.jpg
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
"C:\Program Files (x86)\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive ".\zzzGDB.sqlite3" "https://www.deviantart.com/"%FOLDER%"/gallery/all"
setlocal EnableExtensions DisableDelayedExpansion
for /D %%I in ("U:\11Web\gallery-dl\deviantart\*") do (
if exist "%%I\zzzGDB.sqlite3" (
del "%%I\Folder.jpg"
)
rem
)
endlocal
Note: Currently, the modified code goes back through every single folder within U:\11Web\gallery-dl\deviantart\*. This action should be reserved only to the local folder. I'm guessing the below is the issue.
for /D %%I in ("U:\11Web\gallery-dl\deviantart\*")
I don't know how to remove it and still implement everything after do?
do (
if exist ".\zzzGDB.sqlite3" (
del ".\Folder.jpg"
)
rem
)
I suggest to use following lines for aGallery-dl.bat.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0" || exit /B
move /Y "Folder2.jpg" "Folder.jpg"
for %%I in (.) do set "FOLDER=%%~nxI"
"%ProgramFiles(x86)%\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive "%~dp0zzzGDB.sqlite3" "https://www.deviantart.com/%FOLDER%/gallery/all"
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
popd
endlocal
The first two lines define the execution environment for the batch file.
The third line with command PUSHD pushes the current directory path on stack and sets the directory of the executed batch file as current directory. This works even on batch file being stored on a network resource accessed using a UNC path, except there is a network problem on execution of that command line.
The command exit /B is executed in case of an error to immediately exit processing of the batch file on batch file directory could not be set as current directory. The Windows command processor runs implicitly the command ENDLOCAL in this case.
See Single line with multiple commands using Windows batch file for an explanation of operator || which results in conditionally executing exit /B only if pushd exited with a non-zero exit code indicating an error.
The fourth command line with MOVE does not really move the data of file Folder2.jpg to file with name Folder.jpg. In real it just updates the file system in this case as done also by the two commands del .\Folder.jpg and ren .\Folder2.jpg Folder.jpg in your batch file. This is just a very little bit faster method to replace one file by another file with the advantage that Folder.jpg must not exist at all for success without displaying an error message as done by command DEL on file Folder.jpg not existing.
The FOR command line determines the name of the current folder without path and assigns it to environment variable FOLDER. This is a much faster and safer solution then using the command line:
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
The command line above results in starting in background one more command process with %ComSpec% /c and the command line between ' appended as additional arguments. So there is executed in background with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c cd
The started cmd.exe executes internal command cd which outputs the full qualified folder name of current directory to handle STDOUT of background command process. This output is captured by cmd.exe processing the batch file and is processed by for after started cmd.exe closed itself after finishing execution of command CD.
The command FOR would split up the folder path into substrings (tokens) using normal space and horizontal tab as string delimiters, would look next if the first space/tab delimited string starts with a semicolon in which case the captured line would be ignored for further processing, and would assign otherwise just the first space/tab delimited string to loop variable i. So if the full qualified folder name of current directory would contain a space, this command line would fail to determine the folder name of current directory without path.
There is the dynamic variable CD of which value can be referenced with %CD%. The value is the full qualified folder name of current directory not ending with a backslash, except the root directory of a drive is the current directory. That would be identical to %~dp0 for batch file aGallery-dl.bat with the difference that %~dp0 expands to full qualified name of batch file folder always with a backslash at end.
However, neither dynamic variable CD nor %~dp0 nor execution of command CD in a separate command process in background are really useful to get name of current directory (= batch file directory) without path. The best method is using:
for %%I in (.) do set "FOLDER=%%~nxI"
This simple FOR does nothing else than getting name of current folder without path with a very fast executed file system query and assigning it to environment variable FOLDER.
Note: for %%I in ("%~dp0.") do set "FOLDER=%%~nxI" could be also used to get folder name without path of folder containing currently executed batch file if the current directory would not be the batch file directory.
The sixth command line executes gallery-dl.exe with various parameters (arguments).
Please note that "https://www.deviantart.com/"%FOLDER%"/gallery/all" is in real an invalid argument string. It is not valid to have " inside a URL. The character " is never valid inside an argument string which references a file or folder. This syntax error is detected and automatically fixed which is the reason why the command line in your batch file works at all. The correct argument string is "https://www.deviantart.com/%FOLDER%/gallery/all" with one " at beginning and one " at end and no double quote inside the argument string enclosed in double quotes.
There is standard for console applications to exit with value 0 on success and a greater value like 1 on an error. I don't know if this is true also for gallery-dl.exe, but I assume that with the command line:
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
if not errorlevel 1 checks if exit code of gallery-dl.exe assigned to dynamic variable errorlevel is NOT greater or equal 1 which means less than 1 which means equal 0 (on executable never exiting with a negative value which is not recommended to do by a program on any operating system) which means no error occurred during execution of gallery-dl.exe. Please read the documentation of gallery-dl.exe regarding to exit codes of this program or find it out with several executions in a command prompt window and using echo Exit code is: %errorlevel% after each execution of gallery-dl.exe with success or an error (like a wrong URL).
That condition should be already enough. But there is used one more condition to check for existence of the file zzzGDB.sqlite3 in current directory only before deleting the file Folder.jpg in the current directory which is the batch file directory.
Please read issue 2 in this answer for the reason writing in batch file
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
instead of
if not errorlevel 1 (
if exist "zzzGDB.sqlite3" (
del "Folder.jpg"
)
)
The code above works also, but requires more CPU cycles for being processed by Windows command processor than the single line with two IF commands and one DEL command on one command line.
The last but one line pops the full qualified folder name of initial current directory from stack and sets it again as current directory and the last line restores initial execution environment on starting the batch file.
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 %~dp0 ... drive and path of argument 0 ... full batch file path.
del /?
echo /?
endlocal /?
exit /?
for /?
move /?
popd /?
pushd /?
set /?
setlocal /?
Related
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.
I need a batch script to keep only the newest N files based on the timestamp from filename and only if the size is bigger than 150 KB (if the size is less, means the backed up file is damage and can be deleted).
I found similar scripts but only for Linux.
The script should first delete all the files with size less than 150 KB and keep the newest N files using as reference the timestamp from filename not the modified date of the files.
This .txt file is modify a few times per day except the weekend.
The file is backed up a few times per day and the date and time are added in filename.
Example of filename: Test_2019-01-16_21-57-34.txt
Path is: Z:\
OS is Windows 8
This task could be done with the following batch file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "Z:\" || goto :EOF
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /OS "Test_*.txt" 2^>nul') do if %%~zI LEQ 153600 (del "%%I") else goto DeleteOldFiles
:DeleteOldFiles
for /F "skip=5 eol=| delims=" %%I in ('dir /A-D-H /B /O-N "Test_*.txt" 2^>nul') do del "%%I"
popd
endlocal
The directory Z:\ is set as current directory using command PUSHD with exiting batch file execution with goto :EOF on failure.
Next command FOR executes with cmd.exe /c (more precisely %ComSpec% /c) in a separate command process in background the command line:
dir /A-D-H /B /OS "Test_*.txt" 2>nul
The command DIR outputs
the names of non-hidden files because of option /A-D-H (attribute not directory and not hidden)
in bare format without any additional data because of option /B
ordered by size with smallest file first and largest file last because of option /OS
matching the wildcard pattern Test_*.txt in current directory.
An error message output by DIR on not finding any directory entry in current directory matching these criteria is suppressed by redirecting the error message from handle STDERR 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 written to handle STDOUT of started command process and processes the captured output line by line after started cmd.exe terminated itself.
FOR with option /F ignores empty lines which do not occur here on using DIR with option /B.
FOR would split up each line into substrings (tokens) using normal space and horizontal tab as delimiters and would assign just first space/tab delimited string to specified loop variable I. This line splitting behavior is disabled by using delims= to define an empty list of string delimiters. delims= is not really necessary here in this case because of the file names of the backup files do not contain a space character.
FOR would also ignore lines on which the first substring after splitting up the line into substrings (not necessarily the substring assigned to the loop variable) starts with a semicolon because of ; is the default end of line character. A file name can start with a semicolon and so it is better to redefine end of line character with eol=| or eol=? to vertical bar or question mark which no file name can contain at all. In this case eol=| would not be necessary because output by DIR are only file names starting with Test_ and so the default eol=; does not need to be overwritten with eol=|.
The IF command compares size of current file with value 153600 which is 150 KiB and the file is deleted if its size is less or equal this value.
Note: Windows command processor uses signed 32-bit arithmetic. So a file with more than 2,147,483,647 bytes (2 GiB) is not correct processed by this IF condition. It would be necessary to work around this signed 32-bit arithmetic limitation if backup files can be ever larger than 2 GiB.
Otherwise the first loop is exited with a jump to line below label DeleteOldFiles on current file being larger than 150 KiB because this file and all other files output by DIR after this file have a file size greater than 150 KiB.
The second FOR loop runs again command DIR in a separate command process in background. But the DIR option /OS is replaced by /O-N to get the file names output in reverse order according to file name. The file name with newest date is output first by DIR and the file name with oldest date in name is output last because of using international date format in the file names.
The second FOR command line contains additionally the option skip=5 to skip first five file names, i.e. the newest five backup files.
If DIR outputs more than five file names, all other files being older than the first five output file names are deleted by command DEL executed unconditionally by second FOR.
Finally the initial current directory is set again as current directory using POPD.
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 /?
for /?
goto /?
if /?
popd /?
pushd /?
See also:
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file for an explanation of ||.
One more hint: Replace Z:\ by the UNC path if drive letter Z: is assigned to a network resource. And make sure the batch file is executed by an account which has the permissions to access the network resource and delete files in that folder on network resource in case of this batch file is executed as scheduled task. See also What must be taken into account on executing a batch file as scheduled task?
My Code
I have some straight forward code below that:
Checks if a file exists in my directory
Runs a for loop to get the first filename
Does stuff based on filename
Deletes the file
Checks if any other files exist in directory (if yes, repeat, if not, move on)
:MYLOOP
IF NOT EXIST "%mypath%\*.*" GOTO nofile
FOR %%F IN ("%mypath%\*.*") DO (
set filenameWithExt=%%~nxF
set filename=%%~nF
set filepath=%%~pF
)
do other filename specific tasks
del "%mypath%\%filenameWithExt%"
IF NOT EXIST "%mypath%\*.*" GOTO nofile
GOTO MYLOOP
:nofile
My Issue
I've used this code repeatedly and its worked like a charm, but on my most recent use it looks like its finding a 'ghost' file. When there are no FILES (there is a single archive FOLDER) in the directory, the if not exist check from step 1 above somehow is still passing. As a result, the set code in the for loop results in:
The system cannot find the file specified.
And it then appears as though it tries to delete my directory, saying:
\\mypath*, Are you sure (Y/N)?
I then have to manually terminate an otherwise automated batch.
My Question
Why is it passing the if not exist check, rather than skipping to :nofile?
How can I account for this 'ghost' file (or if it is detecting the archive folder -- how else can I ignore it)?
Windows kernel and therefore also Windows command interpreter interprets the wildcard pattern *.* like * which means any file or folder. On using wildcard pattern *.* it does not mean there must be a file (or folder) with a dot in name.
For that reason using the condition IF NOT EXIST "%mypath%\*.*" is the same as using IF NOT EXIST "%mypath%\*".
IF EXIST "%mypath%\*" is often used in batch files to verify that %mypath% specifies a folder and not a file because this condition checks if there is a folder %mypath%. The condition is true if that folder exists, independent on number of files and folders in that folder.
So the condition at top of your batch file does not check if there is not at least 1 file in folder %mypath%, it checks if this folder does not exist at all.
You could use the following batch code which avoids the usage of delayed expansion by using a subroutine.
#echo off
for /F "delims=" %%I in ('dir /A-D /B /ON "%mypath%\*" 2^>nul') do call :ProcessFile "%mypath%\%%I"
goto :EOF
:ProcessFile
set "FilenNmeWithExt=%~nx1"
set "FileName=%~n1"
set "FilePath=%~p1"
rem do other filename specific tasks
del "%~1"
goto :EOF
The command FOR executes the command line
dir /A-D /B /ON "%mypath%\*" 2>nul
in a separate command process in background and captures the output of DIR written to handle STDOUT.
DIR would output an error message to handle STDERR if the directory does not exist at all or does not contain any file. This error message is suppressed by redirecting it to device NUL using 2>nul. The redirection operator > must be escaped here with caret character ^ to be interpreted first by Windows command interpreter as literal character on parsing the entire FOR command line as otherwise a syntax error would be the result.
Option /A-D means that DIR should output all directory entries NOT having directory attribute set, i.e. just files, not folders. /B changes output of DIR to bare format which means only the file names without any additional data. /ON results in ordering the list by file name before DIR outputs the entire list. This option would not be really necessary here.
FOR processes now the captured output of DIR. So it does not matter that files from that directory are deleted while FOR is running. FOR processes the initial list as output by DIR.
For each file name output by DIR the subroutine ProcessFile is executed which is like calling another batch file with that name. Passed to the subroutine is the file name with its path. DIR outputs just the file name without path on not using additionally /S to get a list of all file names in specified directory and all its subdirectories.
The command goto :EOF after the FOR loop is required to avoid a fall through to the subroutine once all file names output by DIR have been processed.
The command goto :EOF after the subroutine would not be required if the line above is the last line of the batch file. But it is in general good practice to end a subroutine always with goto :EOF in case of ever adding more command lines like another subroutine below. For Windows command interpreter it does not matter where the subroutine starting with its label is located in the file.
The if exist test looks for anything in the directory.
I'd restructure you code:
:MYLOOP
set "found1="
FOR %%F IN ("%mypath%\*.*") DO (
set filenameWithExt=%%~nxF
set filename=%%~nF
set filepath=%%~pF
set "found1=Y"
)
if not defined found1 goto nofile
do other filename specific tasks
del "%mypath%\%filenameWithExt%"
GOTO MYLOOP
:nofile
If the for finds no files, found1 will remain undefined so we go to the :nofile label, else we have a file to process. Having deleted the file, just go back to the beginning, clear the flag and repeat...
I have a project which has following steps:
Create list of jpg files in a folder (initially there is none).
Go to step 1 if the created text file is empty.
Start another program (this program needs the received jpg file as input) if the created list file in step 1 is not empty.
JPG file will be sent to this folder by another process.
I am new to using batch script and used the following code from input.
But this program is not starting another process as required in step 3 even after receiving JPG file.
What is wrong with my code?
#echo off
set "dir=E:\test"
set "file=%dir%\a.txt"
:start
dir/b *.jpg>a.txt
if "%~z1" == "" (
goto start
)
if "%~z1" == "0" (
goto start
)
if "%~z1" == "1" (
Start "" "C:\Users\vamsidhar muthireddy\Documents\Visual Studio 2010\Projects\database_test0\Debug\database_test0.exe"
)
Don't name a variable like an internal command. It is possible to name a variable dir although there is also the command DIR, but it is not advisable.
Don't name a label like an internal command. It is possible to name a label start although there is also the command START, but it is not advisable.
Why is it not advisable to name a variable or label like a command?
Well, for example if in future somebody wants to find where variable dir is used and the batch file contains also command DIR, or wants to rename label start by running a replace and batch file contains also command START, these actions become difficult as it must be analyzed in which context dir and start are used on each found occurrence.
Also syntax highlighting of batch file code is definitely not correct with commands DIR and START as the variable dir and the label start would be most likely also highlighted as commands.
The main coding mistake is %~z1 as this is replaced by file size of the file specified with its file name as first argument on calling the batch file if the batch file was called at all with a file name of an existing file. But this is not the case here. The intention here was getting size of the list file. Also if "%~z1" == "1" will be nearly never true. This condition becomes only true if the file specified as parameter has a file size of exactly 1 byte.
Here is a commented batch code which I think is more useful for the task:
#echo off
set "SourceDirectory=E:\test"
rem This loop is executed with a delay of 5 seconds between each loop run
rem until at least 1 file with extension JPG is found in the defined source
rem directory. Then the JPG file is processed and batch processing ends.
:Loop
echo Checking for a *.jpg file in %SourceDirectory% ...
if exist "%SourceDirectory%\*.jpg" goto ProcessFile
%SystemRoot%\System32\ping.exe 127.0.0.1 -n 6 >nul
goto Loop
:ProcessFile
for %%I in ("%SourceDirectory%\*.jpg") do (
echo Processing %%I ...
start "" "%USERPROFILE%\Documents\Visual Studio 2010\Projects\database_test0\Debug\database_test0.exe" "%%I"
)
rem Delete the created variable before exiting batch processing.
set "SourceDirectory="
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.
echo /?
for /?
goto /?
if /?
ping /?
rem /?
set /?
start /?
I need to verify if any files exist in a folder and if so present the user with a message.
Currently I have this:
IF EXIST C:\PLUS\ADMIN\BATCH\*.* (
start "" cmd/c "echo Files in the directory! &echo (&pause
)
Exit
I've spent hours reading the things I've dug up on variables and piping results to things but I'm a complete batch file newbie so I'm really hoping someone can just tell me what I'm doing wrong.
Currently the batch file runs just fine but it's throwing up the message on the screen regardless of whether there are files in the directory or not. Those files tend to be named 20141010.570, 20141011.571, etc. with variable file extensions based upon an ever increasing number (so it'll stretch into 4 digits once it's done with *.999)
The problem with your code is that in windows all folders contain at least two folders (. and ..) and the test if exist c:\somewhere\* will always be true.
One easy solution is to use dir command asking to only show the files, without directories, and see if it raises an error
dir /a-d "C:\PLUS\ADMIN\BATCH\*" >nul 2>nul && (
start "" cmd /c "#echo Files in the directory! &#echo(&#pause
) || (
echo there are no files
)
The /a-d will exclude folders. If there are files, errorlevel is not set and the code after && is executed. Else, if there are no files, dir command fails, errorlevel is set and the code after || is executed.
for /f %A in ('dir /b^|findstr /i /r "[0-9][0-9][0-9][0-9]*\.[0-9][0-9][0-9]*') do echo %A
or
dir /b|findstr /i /r "\<[0-9][0-9][0-9][0-9]*\.[0-9][0-9][0-9]*\>"&&Echo File Found||Echo File Not Found
The pattern is three or more numeric characters, a dot, then three or more numeric characters, ch. It must be the entire string (so a22222.222 won't match).
Type findstr /? for help. Dos's 6.22 Help files lists return codes as 0 found, 1 not found, and 2 error.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. Single % sign at command prompt and double % sign in a batch file.
.
--
As all the files start with 2014 then you can use this:
IF EXIST "C:\PLUS\ADMIN\BATCH\2*.*" (
echo Files are in the directory!
echo(
pause
)
Exit