StomStom
StomStom

Reputation: 3

Loop through files in a folder and check if they have different extensions

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:

  1. loop through files in the folder
  2. strip each file to its name without extension
  3. check that same name files exist for both .xml and pdf.
  4. if not mark a flag variable as problem
  5. when done, if the flag variable is marked, send an Email notification

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

Answers (4)

aschipfl
aschipfl

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

Compo
Compo

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

Horsing
Horsing

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

SachaDee
SachaDee

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

Related Questions