I would like to create a batch file that will search in a dir for all .pdf files that have a name of 10 characters as we have many .pdf's with different characters in name so I need to sort them out and move (cut and paste) them to a 2nd directory that is prepared. Can you please help me with this batch file?
example
setdir test contain .pdfs
--+6570296402-1-982464371-120.pdf
+6581239585-1-982470028-120.pdf
5710101306.pdf
0-PZ-6562825.pdf
0-PZ-545515247-1-982466351-120.pdf
5455152471.pdf
result:
target dir - test2 - where need to be moved .pdf with 10 characters
5710101306.pdf
5455152471.pdf
etc
Thank you so much
Running from the current directory you could probably do this using Where and Move:
#Echo Off
For /F "Delims=" %%A In ('Where/F .:??????????.pdf'
) Do Move /Y %%A "Test2">Nul
(for /f "delims=" %%a in ('dir /b /a-d *.pdf') do call :select10 "%%a") >filename.txt
... more processing if required
goto :eof
:select10
set "name=%~n1"
set "name=%name:~9%"
if not defined name goto :eof
set "name=%name:~1%"
if not defined name echo %~1
goto :eof
This should solve the problem.
perform a dir list of *.pdf, selecting filenames only. Pass the filename found to subroutine :select10, in quotes in case of spaces in filename.
The subroutine set name first to the name part of the filename received, then removes the first 9 characters. If the result is an empty variable, skip to end-of-file. If not, select all but the first character. If the result is not an empty string, the name must be 11 or more characters - if it's empty, then echo the name passed in the first instance.
The parentheses around the for command will cause the echoed data to be accumulated into the file nominated.
If you want to move the file to the destination, not simply list the selections, remove the ( before the for, and the ) >filename.txt after and replace the echo with move "%1" destination\
You could also do the same without using a subroutine as:
for /f %%a in ('dir /b /a-d *.pdf') do (
set "name=%%~na"
setlocal enabledelayedexpansion
set "name=!name:~9!"
if defined name (
set "name=!name:~1!"
if not defined name move "%%a" destination\
)
endlocal
)
Using delayed expansion to process the substringing operations.
Related
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: ^)
So I am using an application that creates a series of .tif files with very annoying filenames that do not sort correctly in alphanumerical order. I have no way to change the behavior of this commercial software, so I must use my own creativity to rename the files so they may be processed externally in the correct order. For example, the files created look like this:
image.tif, image(2).tif, image(3).tif, ..., image(9).tif, image(10).tif, ..., image(n).tif
Where n is an integer not less than 2. The first file has no number in parenthesis. Sorted alphanumerically, for example, the list would look like:
image.tif, image(10).tif, image(100).tif, image(1000), image(2).tif, ...
Obviously while this is the correct alphanumerical order, it's the incorrect numerical order. So with the aid of some batch commands, I created this:
#echo off & setlocal EnableDelayedExpansion
ren "image.tif" "a.tif"
ren "image(1).tif" "b.tif"
ren "image(2).tif" "c.tif"
ren "image(3).tif" "d.tif"
ren "image(4).tif" "e.tif"
ren "image(5).tif" "f.tif"
ren "image(6).tif" "g.tif"
ren "image(7).tif" "h.tif"
ren "image(8).tif" "i.tif"
ren "image(9).tif" "j.tif"
set a=1
for /f "delims=" %%i in ('dir /b *.tif') do (
ren "%%i" "!a!.tif"
set /a a+=1
)
This at least corrects the names of the first ten files, as I often process less than 100 files. The for loop is a snippet I found here on stackoverflow, it renames the alphanumeric files into integers starting with 1 up to the number of files.
Problem I run into is that this loop still creates 1.tif, 10.tif, and 100.tif that would come before 2.tif.
I've seen the use of %02d to format numbers into 01, 02, 10, etc. Does anyone know how to syntactically include that in the loop shown above?
Or if anyone can figure a more elegant method to rename these files into a suitable alphanumeric order, it would be greatly appreciated. I have the feeling my solution is very kludgey.
#echo off
setlocal EnableDelayedExpansion
rem Initialize "i" variable with the desired number of digits as zeros
set i=1000
rem Process the files in creation date-time order
for /F "delims=" %%a in ('dir /A-D /OD /B *.tif') do (
rem Increment the number: "1001"...
set /A i+=1
rem Omit first digit in number: "1", use the rest: "001"...
ren "%%a" "image(!i:~1!).tif"
)
#echo off
setlocal EnableDelayedExpansion
set /a max=99&set /a numlen=2
if exist "image(100).tif" set /a max=999&set /a numlen=3
for /L %%a in (1,1,%max%) do if exist "image(%%a).tif" set /a newnum=1000+%%a&if not exist "image(!newnum:~-%numlen%!).tif" echo(ren "image(%%a).tif" "image(!newnum:~-%numlen%!).tif"
set /a max+=1
echo(ren "image.tif" "image(!newnum:~-%numlen%!).tif"
[untested]
If "image(100).tif" exists, then we need to rename to (001)..(999). If not, to (01)..(99), so then number-length will be 3 or 2.
for each of the names 1..max, if the file exists, calculate 1000+the file number;take the last 3 or 2 characters and rename. Only attempt to rename if the destination name does not exist, so (6) will be renamed to (006) or (06), (15) to (05) or skipped as (15)=(15) and (123) will also be skipped as (123)=(123)
Finally, rename the image.tif file to (000) or (00)
Note that this will simply echo the required commands to allow verification. Change the echo(ren to ren when verified to actually perform the rename.
The %02d convention for padding numbers is a printf thing, not really applicable to the Windows cmd environment or batch scripting. PowerShell has something similar, but not pure batch. However, you can zero-pad numerals pretty easily using variable substring manipulation.
set /a a=0
for /f "delims=" %%I in ('dir /b *.tif') do (
set "idx=00!a!"
ren "%%~I" "!idx:~-3!%%~xI"
set /a a += 1
)
If you'd prefer to keep the naming convention of image(idx).tif while ensuring the TIF files remain in their intended sequential order, a lazy solution might be to use prename.bat and rename with regexps.
prename /v "s/\((\d)\)/(00\1)/" *.tif
prename /v "s/\((\d\d)\)/(0\1)/" *.tif
In cmd there are no format strings like %02d. However, you can use dir /B to retrieve a plain list of files, findstr to filter for those having a parenthesised numeric suffix in their names or no such suffix at all, for /F to capture the resulting file names and split them into tokens relying on (, ), and sub-string expansion to do the actual left-zero-padding, like in the following example:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_LOCATION=." & rem // (directory containing the files to rename)
set "_PATTERN=*.tif" & rem // (search pattern for the files to rename)
set /A "_DIGITS=4" & rem // (number of proposed digits from 1 to 10)
set "_REGEX1=^[^()][^()]*([0-9][0-9]*)\.tif$" & rem // (filter expression)
set "_REGEX2=^[^()][^()]*\.tif$" & rem // (filter expression)
rem // (the filter expressions ensure wrongly named files not to be processed)
rem // Build zero-padding string:
set "PAD=0000000000" & call set "PAD=%%PAD:~-%_DIGITS%%%"
rem // Loop through all matching files:
for /F "tokens=1-3 delims=()" %%A in ('
dir /B /O:N "%_PATTERN%" ^| findstr /I /R /C:"%_REGEX1%" /C:"%_REGEX2%"
') do (
rem // Check if current file name contains a parenthesised numeric suffix:
if not "%%B"=="" (
rem // Numeric suffix found, so store file name parts and pad number:
set "LEFT=%%A" & set "MID=%PAD%%%B" & set "RIGHT=%%C"
setlocal EnableDelayedExpansion
ECHO rename "!LEFT!(%%B)!RIGHT!" "!LEFT!(!MID:~-%_DIGITS%!)!RIGHT!"
endlocal
) else (
rem // No numeric suffix encountered, so append zero-suffix:
ECHO rename "%%A" "%%~nA(%PAD%)%%~xA"
)
)
endlocal
exit /B
After having successfully verified the appropriate output of the script, remove the upper-case ECHO command to actually rename any files.
The script renames a file like image.tif to image(0000).tif (supposing there is no file named image(0).tif, originally). If you do not want that to happen, simply remove the /C:"%_REGEX2%" part from the findstr command line.
I am a serious newbie at creating batch files and am hoping someone can help me. One of our staff receives zipped pdf docs by email, which she copies to a folder on her desktop. Within that folder, I would like for her to run a batch script that will
A. Unzip the zipped contents into a network directory, i.e. \server\contracts
Under this directory, the process will create folders for each group of contracts, i.e. \server\contracts\Masterson (The name of this will be same as zipped file name).
B. Then the batch process should copy a select few of the pdf documents into a network directory based on the filename. Each file contains a number, which will go in the following manner: Masterson + 1.pdf >> \server\contracts\Item1 and \server\contracts\Item2, etc. Masterson + 1.pdf will go into \server\contracts\Item1 without a folder name, as will Paisley + 1 certificate.pdf and Johnsonville + 1 document.pdf.
The problem is that the companies do not follow instructions and the number can be at the beginning, middle, or end of the file name. Also, unfortunately, there are spaces in the name of the zipped file and the pdf documents. Currently, we are only copying 4 filenames into separate directories for other people to review and validate.
Below is what I did so far looking around this site:
#Echo off
SETLOCAL
for /R "delims=\\server\contracts\RECEIVED 2017-18 APPLICATION" %%I in
("*.zip") do (
"%ProgramFiles(x86)%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
)
rem setlocal enableextensions disabledelayedexpansion
CLS
::The Input Folder
set "InputFolder=C:\Users\eartha.kitt\Desktop\Test"
::The Output Folders
set "Output1=\\server\contracts\ITEM 1 17-18 CERTS"
set "Output6=\\server\contracts\ITEM 6 SIGNATURES"
set "Output8A=\\server\contracts\ITEM 8A 17-18 CALENDARS"
set "Output8B=\\server\contracts\ITEM 8B 16-17 REVISED CALENDARS"
set "Output8a=\\server\contracts\ITEM 8A 17-18 CALENDARS"
set "Output8b=\\server\contracts\ITEM 8B 16-17 REVISED CALENDARS"
::The extensions to wait
set "extensions=*.pdf"
setlocal EnableDelayedExpansion
:Loop
cls
echo Waiting for file ...
for /f "usebackq delims=|" %%a in ('dir /b /s %InputFolder%\%extensions%
2^>nul') do (
rem for /r %%a in in (%InputFolder%\%extensions% 2^>nul') do (
set "Fichier=%%a"
echo Treating _^> %%a
if "!Fichier:~0,-2!"==" 1" COPY "%%~a" %Output1%
if "!Fichier:~0,-2!"==" 6" COPY "%InputFolder%\~%%a" %Output6%
if "!Fichier:~0,-3!"=="8A" COPY "%InputFolder%\%%a" %Output8A%
if "!Fichier:~0,-3!"=="8B" COPY "%InputFolder%\%%a" %Output8B%
if "!Fichier:~0,-3!"=="8a" COPY "%InputFolder%\%%a" %Output8a%
if "!Fichier:~0,-3!"=="8b" COPY "%InputFolder%\%%a" %Output8b%
::Waiting ~5 seconds
ping localhost -n 6 >nul
)
::Return to the loop
goto:Loop
Of course this doesn't work. Please help!
Well - bravo for the attempt! And so close...
Let's take the first part
for /R "delims=\\server\contracts\RECEIVED 2017-18 APPLICATION" %%I in ("*.zip") do (
"%ProgramFiles(x86)%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
)
What's wrong here is that the delims clause is only usable in for /f. for /r always delivers the entire filename to the metavariable %%I.
On my system I use %server%\u for testing - u is a shared resource on the server assigned to U:\ on server.
for /R "\\%server%\u\contracts\RECEIVED 2017-18 APPLICATION" %%I IN ("*.zip") do (
"%ProgramFiles(x86)%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
worked happily for me - delivering the extracted files to "u:\contracts\RECEIVED 2017-18 APPLICATION"
The second part of your code is examining "C:\Users\eartha.kitt\Desktop\Test" not "\%server%\u\contracts\RECEIVED 2017-18 APPLICATION" - very sensibly assigned to a variablename for easy adjustment.
Here's my modified code:
SET "terminatefilename=stop.txt"
DEL "%terminatefilename%" 2>nul
rem setlocal enableextensions disabledelayedexpansion
CLS
::The Input Folder
set "InputFolder=C:\Users\eartha.kitt\Desktop\Test"
set "InputFolder=\\%server%\u\contracts\RECEIVED 2017-18 APPLICATION"
::The Output Folders
set "Output1=\\%server%\u\contracts\ITEM 1 17-18 CERTS"
set "Output6=\\%server%\u\contracts\ITEM 6 SIGNATURES"
set "Output8A=\\%server%\u\contracts\ITEM 8A 17-18 CALENDARS"
set "Output8B=\\%server%\u\contracts\ITEM 8B 16-17 REVISED CALENDARS"
FOR /f "tokens=1*delims==" %%b IN ('set output') DO MD "%%c" 2>nul
::The extensions to wait
set "extensions=*.pdf"
setlocal EnableDelayedExpansion
:Loop
cls
echo Waiting for file ...
for /f "delims=|" %%a in ('dir /b /s "%InputFolder%\%extensions%" 2^>nul') do (
rem for /r %%a in in (%InputFolder%\%extensions% 2^>nul') do (
SET "copied="
echo Treating _^> %%a
REM OPTION 1 - Key string must be at end-of name part
set "Fichier=%%~Na"
if /i "!Fichier:~0,-2!"==" 1" COPY "%%a" "%Output1%"&SET "copied=Y"
if /i "!Fichier:~0,-2!"==" 6" COPY "%%a" "%Output6%"&SET "copied=Y"
if /i "!Fichier:~0,-3!"==" 8A" COPY "%%a" "%Output8A%"&SET "copied=Y"
if /i "!Fichier:~0,-3!"==" 8B" COPY "%%a" "%Output8B%"&SET "copied=Y"
REM OPTION 2 - Key string may be anywhere in filename
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 8B" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output8B%"&SET "copied=Y"
)
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 8A" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output8A%"&SET "copied=Y"
)
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 6" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output6%"&SET "copied=Y"
)
IF NOT DEFINED copied (
echo "%%~na"|FINDSTR /i /L /C:" 1" >NUL
IF NOT ERRORLEVEL 1 COPY "%%a" "%Output1%"&SET "copied=Y"
)
)
::Waiting ~5 seconds
timeout 6 >NUL
:: Test for exit
IF EXIST "%terminatefilename%" DEL "%terminatefilename%"&GOTO :EOF
::Return to the loop
goto:Loop
First, I set up terminatefilename so that creating this file will terminate the batch (it's an infinite loop by design in your code)
Next, I overrode your inputfolder name to suit my system.
Then the output directories. I adjusted their names to suit my system. Note that batch is largely case-insensitive, so setting Output8A and Output8a is setting the same variable. The only time that batch commands are case-sensitive is the metavariable (loop-control variable) in a for statement.
Then I inserted a line to create the destination directories. This uses a set command to list the variables starting output in the format Output1=\\%server%\u\contracts\ITEM 1 17-18 CERTS (where server will have been resolved). The command reads the output of the set command, uses = as the delimiter and assigns output1 to %%b and \\%server%\u\contracts\ITEM 1 17-18 CERTS to %%c. We want to make sure the directory %%c exists, so we make it with an md command and ignore complaints that it already exists with 2>nul.
Next the for/f. for /f reads each line of (thisfilename) or ("this literal value") or ('the output of this command') but when you need to read a from a file whose name must be double-quoted beacuse it contains spaces, then the syntax is for /f "usebackq"... (idontknow) or ("this filename containing spaces") or ('ive no idea whatever') or (`the output of this command`)
So there's no need to use usebackq -- in fact, it's counterproductive.
The delims=| is optional and could be replaced by delims= as the output of a dir command will never contain | (illegal in a file or directoryname). You do need the delims clause however, as the default delimiters include Space and the default tokens is 1 so only the first string of each line output up to the first space will be assigned to %%a.
Hmm - you've remmed-out a for/r. Sadly, the target directory in the for /r can't be a metavariable.
Next, I've cleared a copied flag saying "so far, this file has not been copied"
Next, set fichier to the name-part only of the filename. Since you are using .pdf as a filter, each name output by the for/f will be a full-filename, ending in .pdf
Next, almost-correct with the battery of if statements. The /i makes the comparison case-insensitive so that it will cope with both 8a and 8A. The strings on both sides of the == must be identical to pass the == test, so you need a 3-character string in the 8 tests.
You've evidently been experimenting with the copy command and trying to feed it with appropriate strings. %%~a strips %%a of any enclosing quotes. %%a won't have enclosing quotes - just the fullfilename, so this does nothing in this instance. %InputFolder%\~%%a concatenates the values from InputFolder,"\~" and %%a - which means "%inputfolder%\~%inputfolder%\filenameandextension of %%a". The last two would be resolved to the same, bar the ~.
Since the entire filename is contained in %%a, all that's needed for the sourcefile is "%%a" - quoted as it will probably contain spaces.
Well - the destination directory (we've already established it with the for /f...%%b) can also contain spaces, so it needs to be quoted, too.
I've then set the flag copied to Y if the line took effect. Actually, it can be set to any non-empty value as the whole object is to interpret whether or not it exists with an if defined statement to bypass any later attempts to copy the same file (remember - copied is cleared for each file)
Now - the second option. This is actually a more powerful detector of the required target strings than is the substring version, and will detect the target string anywhere in the filename.
If you echo the name-part only of the file %%~na into a findstr, then set to findstr to look for the /L literal string /i case-insensitive c:"some literal string" and output ny matches found to nowhere (>nul) then findstr will set errorlevel to 0 if found and 1 otherwise. (the /L is superfluous here, I use it habitually to remind me I'm working with literal strings, not regular expressions)
If errorlevel n will be true if errorlevel is currently n or greater than n, so if the string is found, we do the copy and set the copied flag as before.
I reversed the order of tests because it was easier for me to do using the editor I use.
Now - there's a downside to this approach. It's a double-edged sword. Since the target string is detected wherever it appears in the filename, whatever whatever 10 something something.pdf will pass the test for 1 because Space1 appears in its name.
When the loop has finished, use timeout to wait, redirecting the output to nul to make it pipe down. Note that your delay was inside the for loop - so it would have waited 6 seconds after processing each file, not 6 seconds after processing an entire batch.
Finally, if you create terminatefilename from anothe cmd instance, the batch will exit cleanly and kill terminatefilename for you. Much cleaner than control-c.
A last note: Since you are copying the file, not MOVEing it, it will still exist in the same place presumably after the 6 seconds has elapsed and will be endlessly copied and recopied. You'd probably need to make adjustments to achieve the desired result.
Happy Friday Think-Tank!
I need some assistance with a Batch .BAT script. Specifically I need help with some "IF statement syntax"
I have a script that is renaming files. There are two files, one ending in four digits and the other ending in five digits. The files will be renamed with variables I have already pre-set earlier within my script.
So here is a scenario: We have two files in a directory located at
c:\Users\username\Desktop\test-dir
There are two files within test-dir:
file1.12345
file2.1234
A four digit ending is one variable type (VAR1), whereas a file ending in five digits is another variable type (VAR2).
I need an if statement to:
a) read all the files(s) with the chosen directory (without using a wildcard if possible).
b) determine based on the number of digits after the "." which variable to use.
c) once making that determination rename the file with the appropriate variables.
The final re-naming convention is as so: yyyymmddtype.1234/12345
So basically it would use the datestamp variable I already created, the type variable I already created to be injected by the if statement, and append with the original ending digits of the file.
I know this seems like a lot, but I am more so a bash script guy. I have all the elements in place, I just need the if statement and what feels like a for loop of some kind to tie it all together.
Any help would be great!
Thank you!
Sorry, not the option you where asking for. Instead of iterating over the full list checking each file for extension conformance, iterate over a list of patterns that will filter file list, renaming matching files with the asociated "type"
for %%v will iterate over variable list, for %%a will split the content of the variable in pattern and type, for %%f will generate the file list, filter with findstr using the retrieved pattern and rename matching files with the corresponding "type"
Rename command is preceded with a echo to output commands to console. If the output is correct, remove the echo to rename the files.
#echo off
rem Variables defined elsewhere
set "folder=c:\somewhere"
set "timestamp=yyyymmdd"
rem Rename pattern variables in the form pattern;type
set "var1=\.....$;type1"
set "var2=\......$;type2"
set "var1=\.[^.][^.][^.][^.]$;type1"
set "var2=\.[^.][^.][^.][^.][^.]$;type2"
setlocal enableextensions disabledelayedexpansion
for %%v in ("%var1%" "%var2%") do for /f "tokens=1,* delims=;" %%a in ("%%~v") do (
for /f "tokens=*" %%f in ('dir /a-d /b "%folder%" ^| findstr /r /c:"%%~a"') do (
echo ren "%folder%\%%~f" "%timestamp%%%~b%%~xf"
)
)
endlocal
#ECHO OFF &SETLOCAL
set "yyyymmdd=yyyymmdd"
set "VAR1=VAR1"
set "VAR2=VAR2"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\....."') do echo(ren "%%~a" "%yyyymmdd%%VAR1%%%~xa"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\......"') do echo(ren "%%~a" "%yyyymmdd%%VAR2%%%~xa"
remove echo( to get it working.
If I understand you then this will rename the two files using preset variables for each one:
for %%a in ("%userprofile%\Desktop\test-dir\*") do (
if "%%~xa"==".12345" ren "%%a" "%variableA%-%variableB%%%~xa"
) else (
ren "%%a" "%variableC%-%variableD%%%~xa"
)
)
I am creating an MS DOS batch script that needs to list every .bat file in the current directory, but not show autoexec.bat or other utilities or systems .bat files that shouldn't be run by the user.
I currently have DIR "*.bat" /B /P
This lists all .bat files appropriately, but it shows autoexec.bat. How would I exclude that from the list? Also slightly important, how could I chop off the file extensions and show more than the 7-characters DOS limits files to?
Constraints: I am not able to use a DOS version above WinME. That is the version I am using.
Thanks for any help.
EDIT:
There is plenty of information on the internet about doing this, but it is all in the windows command processor, not MS DOS. Please understand that DOS and the Command Prompt are not the same thing.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
echo %%~Na
)
)
EDIT: Some explanations added
Batch file processing is slow, so you should use techniques that allows a Batch file to run faster. For example:
Try to use the minimum lines/commands to achieve a certain result. Try to avoid external commands (*.exe files) like find, findstr, fc, etc. specially if they work on small amounts of data; use if command instead.
Use for %%a in (*.bat)... instead of for /F %%a in ('dir /B *.bat').... The second method requires to execute cmd.exe and store its output in a file before for command can process its lines.
Avoid pipes and use redirections instead. A pipe require the execution of two copies of cmd.exe to process the command at each side of the pipe.
A simple way to check if a variable contain a given string is trying to delete the string from the variable: if the result is different then the string exists in the variable: if "!variable:%string%=!" neq "%variable%" echo The string is in the variable.
Previous method may also be used to check if a variable have anyone of a list of values: set list=one two three, if "!list:%variable%=!" neq "%list%" echo The variable have one value from the list. If the values of the list may have spaces, they must be separated by another delimiter.
EDIT: New version added as answer to new comments
The easiest way to pause one page at a time is to use more filter this way:
theBatchFile | more
However, the program must reorder the output in order to show it in columns. The new version below achieve both things, so it does not require more filter; you just need to set the desired number of columns and rows per page.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
rem Set the first two next variables as desired:
set /A columns=5, rows=41, wide=(80-columns)/columns, col=0, row=0
rem Create filling spaces to align columns
set spaces=
for /L %%a in (1,1,%wide%) do set spaces= !spaces!
set line=
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
rem If this column is less than the limit...
set /A col+=1
if !col! lss %columns% (
rem ... add it to current line
set name=%%~Na%spaces%
set "line=!line!!name:~0,%wide%! "
) else (
rem ... show current line and reset it
set name=%%~Na
echo !line!!name:~0,%wide%!
set line=
set /a col=0, row+=1
rem If this row is equal to the limit...
if !row! equ %rows% (
rem ...do a pause and reset row
pause
set row=0
)
)
)
)
rem Show last line, if any
if defined line echo %line%
Antonio
attrib +h autoexec.bat
should hide autoexec.bat and it should thus not appear in the list
DIR "*.bat" /B /P | find /v "autoexec" | for %i in (*.bat) do #echo %~ni
Using for to process each file name individually:
setlocal enabledelayedexpansion
for /f %%i in ('dir "*.bat" /b') do (
set system=0
if "%%i"=="autoexec.bat" set system=1
if "%%i"=="somesystem.bat" set system=1
if !system!==0 echo %%i
)
Another method without variables:
for /f %%i in ('dir "*.bat" /b') do call :test %%i
goto continue
:test
if "%1"=="autoexec.bat" goto :eof
if "%1"=="somesystem.bat" goto :eof
echo %1
goto :eof
:continue
For both, you can add new filenames to exclude from the list.