Reputation: 3
I have a folder that contains files; each document should have .pdf and .xml format. I need to write a BAT file to run from a scheduled task to verify that both documents exist for each.
My logic is:
I know how to use blat to sending email, but I'm having trouble to execute the loop. I found a way to get path and file name without extension but can't merge them.
I've used batch files a few time, before but I'm far from an expert. What am I missing?
Here's the code I have so far:
set "FolderPath=E:\TestBat\Test\"
echo %FolderPath%
for %%f in (%FolderPath%*) do (
set /p val=<%%f
For %%A in ("%%f") do (
Set Folder=%%~dpA
Set Name=%%~nxA
)
echo Folder is: %Folder%
echo Name is: %Name%
if NOT EXIST %FolderPath%%name%.xml
set flag=MISSING
if NOT EXIST %FolderPath%%name%.pdf
set flag=MISSING
)
echo %Flag%
pause
Upvotes: 0
Views: 7070
Reputation: 34929
Keep it simple:
@echo off
pushd "E:\TestBat\Test" || exit /B 1
for %%F in ("*.pdf") do if not exist "%%~nF.xml" echo %%~nxF
for %%F in ("*.xml") do if not exist "%%~nF.pdf" echo %%~nxF
popd
This returns all files that appear orphaned, that is, where the file with the same name but the other extension (.pdf
, .xml
) is missing. To implement a variable FLAG
to indicate there are missing files, simply append & set "FLAG=missing"
to each for
line and ensure FLAG
is empty initially. Then you can check it later by simply using if defined FLAG
.
Note: This does not cover the e-mail notification issue. Since I do not know the BLAT tool you mentioned, I have no clue how you want to transfer the listed files to it (command line arguments, temporary file, or STDIN stream?).
In case there is a huge number of files in the target directory, another approach might be better in terms of performance, provided that the number of file system accesses is reduced drastically (note that the above script accesses the file system within the for
loop body by if exist
, hence for every iterated file individually). So here is an attempt relying on a temporary file and the findstr
command:
@echo off
pushd "E:\TestBat\Test" || exit /B 1
rem // Return all orphaned `.pdf` files:
call :SUB "*.pdf" "*.xml"
rem // Return all orphaned `.xml` files:
call :SUB "*.xml" "*.pdf"
popd
exit /B
:SUB val_pattern_orphaned val_pattern_missing
set "LIST=%TEMP%\%~n0_%RANDOM%.tmp"
> "%LIST%" (
rem // Retrieve list of files with one extension:
for %%F in ("%~2") do (
rem /* Replace the extension by the other one,
rem then write the list to a temporary file;
rem this constitutes a list of expected files: */
echo(%%~nF%~x1
)
)
rem /* Search actual list of files with the other extension
rem for occurrences of the list of expected files and
rem return each item that does not match: */
dir /B /A:-D "%~1" | findstr /L /I /X /V /G:"%LIST%"
rem // Clean up the temporary file:
del "%LIST%"
exit /B
To understand how it works, let us concentrate on the first sub-routine call call :SUB "*.pdf" "*.xml"
using an example; let us assume the target directory contains the following files:
AlOnE.xml ExtrA.pdf sAmplE.pdf sAmplE.xml
So in the for
loop a list of .xml
files is gathered:
AlOnE.xml sAmplE.xml
This is written to a temporary file but with the extensions .xml
replaced by .pdf
:
AlOnE.pdf sAmplE.pdf
The next step is to generate a list of actually existing .pdf
files:
ExtrA.pdf sAmplE.pdf
This is piped into a findstr
command line, that searches this list for search strings that are gathered from the temporary file, returning non-matching lines only. In other words, findstr
returns only those lines of the input list that do not occur in the temporary file:
ExtrA.pdf
To finally get also orphaned .xml
files, the second sub-routine call is needed.
Since this script uses a temporary file containing a file list which is processed once by findstr
to find any orphaned files per extension, the overall number of file system access operations is lower. The weakest part however is the for
loop (containing string concatenation operations).
Upvotes: 0
Reputation: 38642
There is no need for fancy code for a task such as this:
@Echo Off
Set "FolderPath=E:\TestBat\Test"
If /I Not "%CD%"=="%FolderPath%" PushD "%FolderPath%" 2>Nul||Exit/B
Set "flag="
For %%A In (*.pdf *.xml) Do (
If /I "%%~xA"==".pdf" (If Not Exist "%%~nA.xml" Set "flag=MISSING")
If /I "%%~xA"==".xml" (If Not Exist "%%~nA.pdf" Set "flag=MISSING")
)
If Defined flag Echo=%flag%
Timeout -1
Upvotes: 1
Reputation: 1100
Is this what you want?
@echo off
setlocal enabledelayedexpansion
set "FolderPath=E:\TestBat\Test\"
echo !FolderPath!
for /f "usebackq delims=" %%f in (`dir !FolderPath! /B`) do (
set /p val=<%%f
For %%A in ("%%f") do (
Set Folder=%%~dpA
Set name=%%~nxA
)
echo Folder is: !Folder!
echo Name is: !name!
if NOT EXIST !FolderPath!!name!.xml set flag=MISSING
if NOT EXIST !FolderPath!!name!.pdf set flag=MISSING
)
echo Flag: !flag!
pause
endlocal
You should reformat your code and keep in mind that the grama for batch file is critical. BTW, if you are trying to update the existing batch variable and read it later, you should enable localdelayedexpansion
and use !
instead of %
.
Upvotes: 0
Reputation: 9545
Something like this :
set "FolderPath=E:\TestBat\Test\"
pushd "%FolderPath%"
for %%a in (*.xml) do (
if exist "%%~na.pdf"(
echo ok
) else (
rem do what you want here
echo Missing
)
)
popd
Upvotes: 0