If exist with multiple wildcards - batch-file

These are the requirements:
Specify the wildcards to check in a variable.
For each wildcard, verify if there are files or not. Warn the user if not (just an echo).
Process the resulting files.
What I have tried (applies to only 1 wildcard):
SET wildcard=a*.txt
cd c:\somedirectory
IF EXIST "%wildcard%" (
REM PROCESS THE FILES
) ELSE (
ECHO There are no files that match that wildcard, please review.
)
This obviously only works if the wildcard is unique.
What I have tried:
SET wildcard=a*.txt b*.txt
cd c:\somedirectory
FOR %%A IN (%wildcard%) DO (
ECHO %%A
)
This prints the files that match a*.txt or b*.txt. I do not want that expansion to occur. I need the actual wildcard value to go inside the loop.
With expansion, I cannot tell the user that some his wildcards do not have files. E.g. there are files a*.txt, but no files b*.txt. I need to tell that to the user. Something like:
a*.txt: there are files.
b*.txt: there are no files, please review.
Something like (this does not work, just the idea of what I am looking for):
SET wildcard=a*.txt b*.txt c*.txt
cd c:\somedirectory
REM loop on the wildcards
FOR %%A IN (%wildcard%) DO (
REM verify if there are files for that wildcard
IF EXIST %%A (
REM loop on the files from the specific wildcard
FOR %%F IN (%%A) DO (
REM PROCESS THE FILES
)
) ELSE (
ECHO This pattern %%A has no files associated
)
)
Basically, can I prevent the expansion of values in %wildcard% inside a IF statement?
For #double-beep's comment:
your idea of multiple IF EXIST statements is exactly what I want, but I do not know how many wildcards the user will want.
SET wildcard=a*.txt b*.txt [...]
REM this would be ok
IF EXIST a*.txt ( ... )
IF EXIST b*.txt ( ... )
[...]
But how do I do that flexible, based on what the user puts in the wilcard variable? I thought of looping on the values of wildcard, but FOR does the expansion, which I do not want.

What about this piece of code, using call with parameters, which do not resolve wildcards:
#echo off
set "WildCard=a*.txt b*.txt *.vi"
call :LOOP %WildCard%
rem ...
goto :EOF
:LOOP
if "%~1"=="" goto :EOF
if exist "%~1" echo There are files that match the pattern: "%~1"
shift /0
goto :LOOP

Related

Batch Script To Identify Missing Numerical File Name

I have a custom service that automatically generates files every 60 mins into a particular directory with part of the filename incrementing numerically, Eg:
File_00004.job
File_00003.job
File_00002.job
File_00001.job
Currently I have an issue where on occasion a file isn't generated, which results in gaps in the file sequence. This issue then causes a number of issues if not identified ASAP.
I'd like a batch file to identify if I have a gap in the file name sequence.
Tried looking for solutions from existing posts, but haven't found something that fits, so apologies if this has been covered elsewhere.
#ECHO OFF
SETLOCAL enabledelayedexpansion
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files\t w o"
SET "mask=file_??????.job"
SET "lowest="
SET "highest="
FOR /f "delims=" %%a IN (
'dir /b /a-d /on "%sourcedir%\%mask%" '
) DO (
IF NOT DEFINED lowest SET "lowest=%%~na"
SET "highest=%%~na"
)
SET "lowest=%lowest:*_=1%"
SET "highest=%highest:*_=1%"
ECHO checking range %lowest:~1% to %highest:~1%
:: See whether an entry in the range is missing; report&create an empty file if so.
FOR /L %%a IN (%lowest%,1,%highest%) DO SET "name=%%a"&SET "name=file_!name:~1!.job"&IF NOT EXIST "%sourcedir%\!name!" echo !name! missing&(copy nul "%sourcedir%\!name!" >nul)
GOTO :EOF
Alternative structure for the for /L loop:
FOR /L %%a IN (%lowest%,1,%highest%) DO (
SET "name=%%a"
SET "name=file_!name:~1!.job"
IF NOT EXIST "%sourcedir%\!name!" (
echo !name! missing
copy nul "%sourcedir%\!name!" >nul
copy "d:\path to\template.file" "wherever\!name!" >nul
copy "d:\path to\template.file" "anotherplace\!name!" >nul
echo Batch is fun and powerful
copy "d:\path to\template.file" "a third place\!name!" >nul
)
)
The critical point is the positioning of the ( - must be directly after and on the same line as do or else or the logical comparison clause of if and must be matched by a ) (which doesn't need to be on its own line - I find it easier that way, to align indentation.) )s that are not intended to close a block need to be escaped with ^, thus: ^)

Batch script - Create folder issue

I'm trying to create a batch script that creates folders based on lines in a text file. I want to be able to automate the "D" function so no typing required.
#echo off
set /P D="Enter Name e.g. ABCD:"
for /F "delims=" %%a in (list.txt) DO (
FOR %%x IN (
"C:\test\%D%\%%a"
"C:\test\%D%\%%a\Folder1"
"C:\test\%D%\%%a\Folder2"
) DO (
MD "%%~x"
)
)
My List file looks like this
JACK-12345
JOHN-12345
I'm wanting to read the first 4 characters of each line and create directories in relevant folders that already exist.
So JACK-12345 will create a folder in C:\test\JACK\JACK-12345 and JOHN will create a folder C:\test\JOHN\JOHN-12345
Any help would be greatly appreciated!
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "targetdir=U:\destdir"
for /F "delims=" %%a in (q35285628.txt) DO (
SET "ch4=%%a"
SET "ch4=!ch4:~0,4!"
FOR %%x IN (
"%targetdir%\!ch4!\%%a"
"%targetdir%\!ch4!\%%a\Folder1"
"%targetdir%\!ch4!\%%a\Folder2"
) DO (
ECHO(MD "%%~x"
)
)
GOTO :EOF
You would need to change the setting of targetdir to suit your circumstances.
I used a file named q35285628.txt containing your data for my testing.
The required MD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MD to MD to actually create the directories. Append 2>nul to suppress error messages (eg. when the directory already exists)
Invoke delayedexpansion to allow substringing of the metavariable %%a Assig the entire string as read to ch4 then select the first 4 characters.
!var! required within the block to access the changing value of the variable at run-time.
For the extended question (unspecified : where "maths" etc fits into the tree - additional, replacement, whatever??
Using the "meat" of the routine:
SET "ch4=%%a"
SET "ch4=!ch4:~0,4!"
SET "folder1=Folder1"
if /i "!ch4:~0,1!"=="m" SET "folder1=Maths"
if /i "!ch4:~0,1!"=="s" SET "folder1=Science"
FOR %%x IN (
"%targetdir%\!ch4!\%%a"
"%targetdir%\!ch4!\%%a\!folder1!"
"%targetdir%\!ch4!\%%a\Folder2"
) DO (
ECHO(MD "%%~x"
)
)
would replace "folder1" from the original scheme with "Maths" if the first character of the line read from the file was "m" (in either case), "Science" if it was "s" and "Folder1" otherwise.

How to choose one of multiple actions based on file extension, in batch

I'm an amateur on the usage of the FOR command. I need a batch file that will run one of 5 file conversion tools based on a file's extension. I want to drop a file onto the batch file icon and have it converted.
Since my list is huge, I can't use nested IF's.
What I've tried so far:
#ECHO OFF
SET cadfile=.dwg .dxf .dwf
SET gsfile=.ps .eps .epi .epsp
SET xxxxxx=.xx .xx and goes on
FOR %%~x1 in (%cadfile%) do (
Do some action
FOR %%~x1 in (%gsfile%) do (
Do some other action
)
)
The %%~x1 variable is used for file extension of file, which dragged and dropped over the batch file.
(edited to make more clear)
FOR %%a in (%cadfile%) do (
if /i "%~x1"=="%%a" some_action "%~1"
)
... and follow the bouncing ball for the rest of the utilities/lists
I think this will work for you. It looks through all your groups of extensions in a single For loop and when the matching extension is found, calls a label where you can do the conversion and any related tasks. You'll need to finish the "groupN" variables and labels.
#echo off
SETLOCAL EnableDelayedExpansion
set file="%1"
set ext=%~x1
:: Set the 5 groups of extensions that have different converters
set group1=.dwg, .dxf, .dwf
set group2=.ps, .eps, .epi, .epsp
For %%A in (1 2 3 4 5) do (
set groupnum=group%%A
call set thisgroup=%%!groupnum!%%
:: Look for extension in this group
echo.!thisgroup!|findstr /i /C:"%ext%" >nul 2>&1
if not errorlevel 1 call :group%%A
:: else go loop next group
)
echo Extension not found in any group &pause &goto end
:group1
echo group1 file to convert is %file%
goto end
:group2
echo group2 file to convert is %file%
goto end
:end
pause
exit
The following method allows you to easily add and modify your list of extensions/applications. Please note that you just need to edit the values placed inside the first FOR command; the rest of the program is the solution you don't need to care of...
#echo off
setlocal EnableDelayedExpansion
rem Define the list of extensions per application:
rem (this is the only part that you must edit)
for %%a in ("cadfile=.dwg .dxf .dwf"
"gsfile=.ps .eps .epi .epsp"
"xxxxxx=.xx .xx1 .xx2") do (
rem The rest of the code is commented just to be clear,
rem but you may omit the reading of this part if you wish
rem Separate application from its extensions
rem and create a vector called "ext" with an element for each pair
for /F "tokens=1,2 delims==" %%b in (%%a) do (
rem For example: %%b=cadfile, %%c=.dwg .dxf .dwf
for %%d in (%%c) do set "ext[%%d]=%%b"
rem For example: set "ext[.dwg]=cadfile", set "ext[.dxf]=cadfile", set "ext[.dwf]=cadfile"
rem In the next line: set "ext[.ps]=gsfile", set "ext[.eps]=gsfile", etc...
)
)
rem Now process the extension of the file given in the parameter:
if defined ext[%~x1] goto !ext[%~x1]!
echo There is no registered conversion tool for %~x1 extension
goto :EOF
:cadfile
echo Execute cadfile on %1 file
rem cadfile %1
goto :EOF
:gsfile
echo Execute gsfile on %1 file
rem gsfile %1
goto :EOF
etc...
If each conversion tool is executed in the same way and don't require additional parameters (just the filename), then you may omit the individual sections and directly execute the conversion tools this way:
if defined ext[%~x1] !ext[%~x1]! %1
For further explanations on array concept, see this post.

Windows script to rename and move files with arguments

I have been trying to create a script that check file name, if positive, then rename it and move it to a folder in a server, then check for next argument and do the same thing.
The complete idea is that, I have a system that produces CSV files, the name of the file is generated depending of the area, if I am in Nursing, it will generate a file with the word "Nursing" somewhere, so this will help me for scripting purposes to recognise where to put this file using scripts. It will have to read 3 more arguments but I have just mentioned 2 below.
Filename : testing.bat (I am creating a loop)
This is my code so far.
if exist "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Nursing*.csv" (
ren "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Nursing*.csv" names.csv
move /y "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\names.csv" \\10.10.10.10\scenarios\Nursing
)
else if exist "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Midwifery*.csv" (
ren "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Midwifery*.csv" names.csv
move /y "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\names.csv" \\10.10.10.10\scenarios\Midwifery
)
else (
echo. Not files detected!
)
timeout /t 1
testing.bat
Any help is welcome.
You have a syntax problem : the locations of the else clauses. It MUST be placed (when used) in the same line that the closing parenthesis of the if command. If you place it in the next line, the parser will take it as another command, not the continuation of the previous if
if exist .... (
....
) else if exist .... (
....
) else (
....
)
Also, while not being a problem, it is easier to place the paths you are using inside variables and use the variables instead of the literals
set "sourceFolder=E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV"
set "targetFolder=\\10.10.10.10\scenarios"
if exist "%sourceFolder%\*Nursing*.csv" (
ren "%sourceFolder%\*Nursing*.csv" names.csv
move /y "%sourceFolder%\names.csv" "%targetFolder%\Nursing"
) else if exist ""%sourceFolder%\*Midwifery*.csv" (
ren "%sourceFolder%\*Midwifery*.csv" names.csv
move /y "%sourceFolder%\names.csv" "%targetFolder%\Midwifery"
) else (
echo. Not files detected!
)
And once we are using variables to store the fixed data, we can start to use variables to hold the changing data. As the code being executed is always the same, identify the changing parts in the executed code and use for commands to iterate over the changing information and files on folders
#echo off
setlocal enableextensions disabledelayedexpansion
set "sourceFolder=E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV"
set "targetFolder=\\10.10.10.10\scenarios"
for /l %%z in (0) do (
setlocal enabledelayedexpansion
echo(!time! - Searching files ....
endlocal
set "found="
for %%a in ( Nursing Midwifery XXXX YYYY ) do (
for %%b in ("%sourceFolder%\*%%~a*.csv") do (
move /y "%%~fb" "%targetFolder%\%%~a\names.csv"
set "found=1"
)
)
if not defined found echo(.... No file detected !
timeout /t 1
echo(
)
for /l %%z defines an infinite loop (just to avoid the self call in the batch file or a goto command to a label)
for %%a will iterate over the list of "arguments". For each element in the list, the replaceable parameter %%a will hold its value and expose it to the code in the do clause, where %%~a (the value inside the replaceable parameter without quotes if present) is used to search files and determine target folder.
for %%b will search files. In this case the replaceable parameter %%b will hold a reference to the found file. This reference is later used to move the file (%%~fb is the full path to the file being referenced by %%b)
Maybe something like this. You can expand this by having a list of the file names you want to check against the server's directory. So the script then will loop at the files that matches that of your target list.
#echo off
SETLOCAL
if not exist \\deviceName\e$\directory\filename.csv (
echo filename.csv not found!
) else (
ren \\deviceName\e$\directory\filename.csv filename2.csv
move /-Y \\deviceName\e$\directory\filename2.csv \\deviceName2\e$\director\filename2.csv
if not exist \\device\e$\diretory\filename3.csv (
echo filename3.csv not found!
) else (
ren \\deviceName\e$\directory\filename3.csv filename4.csv
move /-Y \\deviceName\e$\directory\filename4.csv \\!deviceName2\e$\director\filename4.csv
)
)
ENDLOCAL
EXIT
Here is a powershell script that will cleanly handle an arbitrary number of departments and still be easy to maintain.
$DepartmentList = "Nursing","Midwifery","Ortho","Pedi"
$SourceFolder = "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV"
$DestFolder = "\\10.10.10.10\scenarios\"
ForEach($Dept in $DepartmentList)
{
if(Test-Path "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*$Dept*.csv")
{
Move-Item "$SourceFolder\*$Dept*.csv" -Destination "$DestFolder\$Dept\names.csv" -Force
$FileFound = $true
}
}
If(-not ($FileFound))
{
Write-Warning "Not files detected!"
}
If you are not using powershell yet, this is a great starter project to make that switch with.

Windows CMD - set within for loop is not working

I want to write batch file which will loop through all directories containing backup directory and remove files older than X days within it.
On computer which I want run my script there's no "forfile" command.
There's no PowerShell, so CMD or VBScripts seems to be only way of accomplishing this task.
Currently I have problem with "set" statement - it seems that when I'm calling %checkpath% I didn't receive expected folder.
rem we will memorize current directory
pushd %cd%
set folder="C:\Documents and Settings\myname\Desktop"
cd %folder%
rem loop only folders with five chars within their names (unfortunately on less also
for /D %%g in (?????) DO (
set checkpath="%cd%\%%g\backup"
if exist %checkpath% (
for %%a in ('%%g\backup\*.*') do (
set FileDate=%%~ta
set FileDate=%%FileDate:~0,10%%
rem here I want to compare file modification data with current date
)
)
popd
pause
You need to use delayed expansion to read a variable that you have set inside a for loop.
Try this instead
setlocal enabledelayedexpansion
rem we will memorize current directory
pushd %cd%
set folder="C:\Documents and Settings\myname\Desktop"
cd %folder%
rem loop only folders with five chars within their names (unfortunately on less also
for /D %%g in (?????) DO (
set checkpath="%cd%\%%g\backup"
if exist !checkpath! (
for %%a in ('%%g\backup\*.*') do (
set FileDate=%%~ta
set FileDate=!%FileDate:~0,10%!
rem here I want to compare file modification data with current date
)
)
popd
pause
Replacing the %'s with !'s on variables you have created will signal it to use delayed expansion instead.
Bali's answer has a slight mistake. The second set filedate is incorrect, otherwise his is fine, but may not work if you do not have delayed expansion enabled. I fixed his mistake and showed you how to ensure delayed expansion is enabled. I have also made some other changes:
::This command will ensure that the delayed expansion, i.e. the "!"s below,
:: will work. Unfortunately, it also means you loose the results of any
:: "set" commands as soon as you execute the "endlocal" below.
setlocal ENABLEDELAYEDEXPANSION
::you might want
::set "folder=%USERPROFILE%\Desktop"
set "folder=C:\Documents and Settings\myname\Desktop"
rem we will memorize current directory
::If you ran this code with the current directory set to a directory on
::a drive other than C:, your previous code would not have worked to
:: change to your desired target directory. this slight change fixes that.
pushd "%folder%"
rem loop only folders with five chars within their names - unfortunately on less also
::Use capitals for your loop variables. The var names are case sensitive, and
::using capitals ensures there is no confusion between the var names and ~modifiers
for /D %%G in ( ????? ) DO (
set checkpath="%CD%\%%G\backup"
if exist !checkpath! (
for %%A in ('%%G\backup\*.*') do (
set FileDate=%%~tA
set FileDate=!FileDate:~0,10!
rem here I want to compare file modification data with current date
)
)
popd
endlocal
pause
But, you don't need the "setlocal" or delayed expansion if you write it like this:
::you might want
::set "folder=%USERPROFILE%\Desktop"
set "folder=C:\Documents and Settings\myname\Desktop"
rem we will memorize current directory
::If you ran this code with the current directory set to a directory on
::a drive other than C:, your previous code would not have worked to
:: change to your desired target directory. this slight change fixes that.
pushd "%folder%"
rem loop only folders with five chars within their names - unfortunately on less also
for /D %%G in ( ????? ) DO (
if exist "%%~G\backup" (
for %%A in ('%%~G\backup\*.*') do (
for /F "usebackq" %%T in ( '%%~tA' ) do (
echo File date is %%T, todays date is %DATE%
)
)
)
popd
pause

Resources