Batch wildcard strange behavior - windows

I have a list of files that I'm looping through that match a certain size letter (A,B,C,D). The files are of the form ###T#####A###_# rev 1.dxf, where the rev 1 is only there some of the time, and A refers to the size, which is A, B, C, or D. When I try to loop through these in a set D.dxf or B.dxf, some A files are also found. I currently use the pattern ?????????A*.dxf, but would like to expand this to more file types without having to make multiple batch files. Interestingly, if I use the pattern TA*.dxf, the wildcard behaves normally.
Why does this happen, and how can I fix it while still being to catch files where the A may be at the beginning, end, middle, etc? If you need any clarification or extra information, feel free to ask.
Here is my relevant code:
FOR %%S IN (A,B,C,D) DO (
echo Converting size %%S. . .
FOR %%F in ("%filepath%\?????????%%S*.dxf") DO (
echo Converting %%~nxF to PDF, size %%S
SET %%S=!%%S! "%%~pF%%~nF.pdf"
"C:\Program Files\AutoDWG\AutoDWG DWG to PDF Converter\d2p.exe" /InFile %%~fF /OutFile %%~nF.pdf /Watermark %~dp0%%Swatermark.wdf /InConfigFile %~dp0%%S.ddp
)
echo:
echo Combining %%Ss. . .
pdftk !%%S! cat output "%filepath%\print\%%Ss.pdf"
echo Combined
echo:
)
EDIT: I'm running this on 32-bit Windows XP. Does this have anything to do with this thread? I will investigate when I get home.
EDIT 2: I've now figured out what the problem is. When I have several files with the same beginning characters, the 8.3 short names contain a hexadecimal number, which may match one of the letters I'm searching for. How can I discard short name matches in my for loop?

Your link to the Strange Windows DIR command behavior thread seems to be a good thought. From RBerteig's thorough answer: Wild cards at the command prompt are matched against both the long file name and the short "8.3" name if one is present.... Try next approach:
SETLOCAL enableextensions enabledelayedexpansion
:::
pushd %filepath%
FOR %%F in ("*.dxf") DO (
set "fname=%%~nF"
set "fmatch="
set "char04=!fname:~3,1!"
set "char10=!fname:~9,1!"
if /I "!char04!"=="T" (
FOR %%S in (A B C D) do if /I "!char10!"=="%%S" set "fmatch=!fname!"
)
if defined fmatch (
echo Converting %%~nxF to PDF, size !char10!
rem another stuff here
)
)
popd

Related

What am I doing wrong in my windows batch script, I'm trying to understand the logic behind script

So here is a bat script that is working, it is removing letter P from every jpg files that start with letter P in a folder.
#echo off
for %%a in (p*.*) do ren "p*" "/*"
I want to understand the logic behind this script, so I'm messing around with it.
If I want remove letter P at end of files, I changed it but it didn't work,
What exactly am I doing wrong?
All I need to move P from beginning to end in the %%a and after ren command.
#echo off
for %%a in (*.*P) do ren "*P" "/*"
You mention that you specifically want to rename the file starting with p and have a .jpg extension. Meaning you want to move the starting p to the end of the name, before the extension. This example does exactly that:
#echo off
setlocal enabledelayedexpansiob
Pushd "D:\location of files here"
for %%i in (p*.jpg) do (
set "name=%%~ni"
ren "!name:~1!!name:~0,1!%%~xi"
)
Popd
Short explanation. We do for p*.jpg to ensure we only iterate through files starting with p and have a jpg extension.
We set the variable %name% to the name only of the file %%~ni (also seen as !name! because we have enabled delayedexpansion)
We then use variable expansion to strip parts of the name. Here we say print everything in the variable !name! excluding the first character as !name:~1!
Then use only the first character as starting from character zero, selecting only one. !name:~0,1! and simply give it back the extension %%~xi
To read more on the help of everything we have used here, open cmd and type the following:
for /?
set /?
setlocal /?
Everything we mentioned in this answer, is available in the help of the above.

Writing a batch file program using wildcards

Write a batch program called EX4.BAT which lists all files matching any of the following criteria within the root of the C: drive and down through its subdirectories:
a) Files with an extension of .COM and have 4 letters in the filename. e.g. chcp.com, mode.com etc.
b) .EXE files whose 2nd letter is I e.g., WINHELP.EXE DIAGS.EXE etc.
Make sure the output does not scroll up the screen too quickly.
Put a pause command in between parts a) and b)
I tried the following :
cd\ Rem to return to the root folder of C
dir ????.com /b/s Rem COM files with 4 letters
pause Rem to pause the screen
dir ?I*.exe /s Rem search EXE files whose 2nd letter is I
For part a), doing this like that accept also numbers, I have to make sure that it accepts only letters. I tried to make use of regular expression but in vain.
Here is a basic example of one method of performing the task laid out in your question, and without the clarification requested in the comment area.
#Echo Off
Setlocal EnableExtensions
Set "PATHEXT="
( "%__APPDIR__%where.exe" /R C:\ ????.com |^
"%__APPDIR__%findstr.exe" /E /I /R "\\[a-Z]*\.com"
Echo(
Echo Press any key to continue . . .
Pause 1> NUL
"%__APPDIR__%where.exe" /R C:\ ?I*.exe
) 2> NUL | "%__APPDIR__%more.com"
EndLocal
Pause
As this is clearly 'homework' I will not be providing any explanation of the commands I have used, or why I have done so, I will also not be adjusting my code to cater for later additions or changes in the task. It is also important to remember, that as this is technically somebody else's submission, you must not present it unless you fully understand how and why it works.

Using a batch to sort through a complex of folders and sort any files with a specific string in their name to a specific directory?

So I have a collection of art from the internet; it is very large and spans an extreme amount of subdirectories under the main folder I keep it all under (entitled Uda). I've built up this collection over a period of about 4 years. In the most recent 2 years, I've been organising things I save by artist (most of this comes from the site DeviantArt if it matters). But I have 2 years' worth of files unsorted, all over the place and I'd like to sort them.
I figure this is an ideal time to practice some batch scripting, but... I've not the faintest idea where to start. Google hasn't been very helpful, it's too hard to explain what I want to do in one question, let alone find someone who has needed the same thing and been guided through it. Also, I'd honestly much prefer to pull apart and figure out an already-made script to understand it and learn from it (that's how I tend to learn best).
So can anyone help me? If you don't understand what I want to do:
I wish to make a script where I can input something (i.e. an artist's name) and have a folder made for it under a certain directory (no matter where the batch is being run from or the files drawn from) with the name of the term that was entered, and then all files under another directory with that term found and moved.
For the record, even if I weren't interested in batch scripting, I couldn't use Windows Explorer to search for them all then cut them because I disabled it (for personal reasons).
#ECHO OFF
SETLOCAL
:: Note that SPACES are significant in simple SET statements
:: Set relative or local root (start-point of subtree to scan)
:: Use normal then safemethod 1 then safemethod2 - all do the same thing
:: Note : from the prompt,
:: command /?
:: will generally show help...
SET relroot=c:\wherever
(SET relroot=c:\wherever)
SET "relroot=c:\wherever"
:: repeat for destination directory
SET "destdir=c:\destination"
::
:: Read Artist
:: Make sure ARTISTS has no existing value, then prompt for input
::
:again
(SET artist=)
SET /p artist="Artist ? "
::
:: Check for input, exit if none
:: Note :EOF is a special predefined label meaning "END OF FILE"
:: character case is generally insignificant
::
IF NOT DEFINED artist GOTO :eof
::
:: make a new directory
:: the 2>nul suppresses an error message like 'it already exists'
:: In quotes in case variables contain spaces
MD "%destdir%\%artist%" 2>nul
::
:: Now look for filenames containing the data entered
:: Note: here, the metavariable %%i IS Case-sensitive
:: >nul means 'don't show message like '1 file(s) moved'
FOR /f "delims=" %%i IN (
' dir /s /b /a-d "%relroot%\*%artist%*" '
) DO (
ECHO %%i
IF EXIST "%destdir%\%artist%\%%~nxi" (
ECHO Cannot MOVE "%%i" because "%destdir%\%artist%\%%~nxi" exists
) else (ECHO MOVE "%%i" "%destdir%\%artist%\%%~nxi" >nul)
)
GOTO again
Well, here's a starter script - assuming that artists' names are in the filename.
Most of the documentation is in-line.
Note that the ::... form of documentation is actually a broken-label and is inadvisable within loops and parenthesised code generally - use REM there. It is however easier to type and less intrusive
The FOR loop needs a little explanation: much of it can be deciphered with a bit of persistence from the documentation
for /?
from the prompt. But the heads-up is:
for /f reads a "file" line-by-line and applies each successive line to the metavariable after being tokenised between delimiters. You can specify the tokens by number counting from 1 and the delimiters are any characters appearing between the delims= and the closing quote. Default delimiters are [space],[tab],[comma],[semicolon] and default tokens is 1. "delims=" specifies that there are no delimiters, so the entire line is applied to the metavariable.
It's possible to use this facility on a data line like Wed. 07/11/2012 by using FOR/f "tokens=2,3,4delims=/ " %%i in... to apply 07 to %%i, 11 to %%j and 2012 to %%k - the tokens are Wed.,07,11 and 2012 when the line is tokenised using [either space or /] and the 2nd token is applied to the loop metavariable %%i, the third to %%j and so on through the list of token numbers. The special token "*" means 'the rest of the line following the highest-number token nominated'
AND.. a single-quoted "filename" is the output of a command. dir /s /b /a-d "%relroot%\*%artist%*" is the directorylist in /b basic form (filenames only) /s scan subdirectories /a-d but don't mention the war directorynames starting at %relroot% and having %artist% somewhere in the filename - all quoted in case spaces are present.
I wont write it for you but, but here is a list of roughly the things you have to achieve. Try looking for each of those and then combine them
input a name
create a directory with this name
find the files with this name
move found files to the directory
if you post code of what you are trying i'll gladly help you.

Batch file for loop string replacement

I have a batch file that take a directory path as a parameter.
In that file folder, there are any number of .ai.pdf or .pdf files that I need to convert to jpg's. The conversion is not my issue (I am using imageMagick) , but lopping off the full extension is.
I need to be able to either take off the full .ai.pdf (7 characters) or .pdf (4 characters) from the file name and replace it with .jpg I cannot use just ~n in the for loop because it will not take off the .ai in an instance with there is an .ai.pdf (results in file name.ai where I need just the file name)
There are quite a few posts on StackOverFlow about this
StackOverFlow Example
but no matter what I attempt to try, I get an error when truncating the appropriate amount of extension off of the file name.
Here is my code. This is the first major batch file I have ever created, so I am open to anything, other than installing more programs to do the work.
The thing that kills me, is I had this working and in the shuffle from one server to another and a week of vacation, the working code got....misplaced.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set dir1=%1
echo recieved !dir1!
for /R %dir1% %%a in (*.pdf) DO (
echo file found !a!
set b=th_%%~nxa
if x%b:ai.pdf=%==x%b% set b=%%~dpa!b:~0,-7!
if not x%b:ai.pdf=%==x%b% set b=%%~dpa!b:~0,-4!
REM convert -density 64 "%%a" +matte -resize 15%% "!b!.jpg"
#echo !b! converted
)
ENDLOCAL
the file tells me that %~dpa!b:~0,-7! is an invalid substitution
Any ideas? Thanks for the help!
A few things first:
!a! and %%a are two different variables.
if x%b:ai.pdf=%==x%b% does not mean what you think it does. That will only be true when %b% does NOT contain .ai.pdf.
Again, if not x%b:ai.pdf=%==x%b% does not mean what you think. This is true when %b% DOES contain .ai.pdf.
There is no need to do any verification and cutting, just search and replace. ( That is what the %y:x=z% notation does, in this example it replaces every x within %y% with a z.) Let search and replace do the verification. It will only replace what matches the search. That will speed up the your batch file.
Lastly, since you are inside a () code block you will need to use the delayed Expansion turned on with your setlocal statement. This is because everything inside a code block is treated as if it were on a single line. That means that if you change a variable inside a code block, you will not be able to see the new value using the % notation. Instead you need to replace the %'s with !'s. For instance...
setlocal enableDelayedExpansion
set x=Hello
(
set x=Goodbye
echo I don't know why you say "!x!", I say "%x%".
)
...will give you the old Beatles lyric...
I don't know why you say "Goodbye", I say "Hello".
Anyway, on to your answer:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set dir1=%1
echo recieved !dir1!
for /R %dir1% %%a in (*.pdf) DO (
:: Adding a colon to the end of the filename allows the extension to be ID'd
: without explicitly looking at it with an IF statement, while simultaneously
:: avoiding similar looking character groupings inside the filename.
set b=th_%%~nxa:
:: No need to check for case, the substitution will do that for you.
set b=!b:.ai.pdf:=.jpg!
set b=!b:.pdf:=.jpg!
REM convert -density 64 "%%a" +matte -resize 15%% "!b!"
echo %%a converted into !b!
)
ENDLOCAL
The drawback is that both the files...
X.ai.pdf
X.pdf
...will be translated into th_X.jpg, creating the possibility of duplicate filenames for two different files.
But that's intrinsic to your concept of treating both types of filenames the same. If you don't have a method for avoiding this sort of duplication it might not be a bad idea to leave the .ai on the file, thereby creating two files: th_X.jpg and th_X.ai.jpg, eliminating the possibility of duplicate filenames.
Hm... would this work for you:
for /R %F in (*.pdf) do #for %G in ("%~nF") do #echo %~nxF ==^> %~nG.jpg
(as executed directly from cmd, if run from batch, replace % with %%).
This has a peculiar effect of changing the case of a file to case of a directory if there exists one with the same name as base name of your file (file.pdf will become FILE.jpg if you happen to have a subdirectory called FILE), but that's it (I think).
This also assumes your base names differ (so no file.ai.pdf and file.pdf in same directory)

How to rename and add incrementing number suffix on multiple files in Batch Script?

I have 500 files coming in and I need to first check if any file(s) exist then rename all of them regardless of what their filename is (the files are named in a different language).
No need to process them in any order.
Rename:
1. “¦X¼d¬f-20110703-¦+¦dñHÑ-ª-¦=¬¦.xls”
2. “¦X¼d¬f-20110707-¦+¡¦-+¡8.xls”
3. “¦X¼d¬f-20110707-¦+¡¦ñj¦«.xls”
4. “¦X¼d¬f-20110708-¦+¡¦¬M¼n.xls”
5. “¦X¼d¬f-20110713-¦d¼O¼n¦hÑP.xls”
.
.
.
500
To:
“TWN_CH_INV_VISIT_FORM_01.xls”
“TWN_CH_INV_VISIT_FORM_02.xls”
“TWN_CH_INV_VISIT_FORM_03.xls”
“TWN_CH_INV_VISIT_FORM_04.xls”
“TWN_CH_INV_VISIT_FORM_05.xls”
.
.
.
“TWN_CH_INV_VISIT_FORM_500.xls”
Hope you could help me on this one. I’ve been trying to do this for weeks.
a simple FOR with a count (SET /A) should do what you need.
setlocal enabledelayedexpansion
SET /A COUNT=0
FOR %%A IN (*.xls) DO (
SET /A COUNT+=1
REN "%%A" "TWN_CH_INV_VIST_FORM_!COUNT!.xls"
)
See HELP FOR and HELP SET
This is a deceptively difficult question to solve.
The 5 year old PA answer has a few problems.
1) The FOR loop begins iterating without buffering the entire directory tree, so it has the potential to rename a file that has already been renamed. I believe that is why the 7 file is missing within r0mmel's comment.
2) Delayed expansion occurs after for variables are expanded, so the file name will be corrupted and the rename will fail if the name contains a ! character.
3) A rename can fail if there already exists a TWN_CH_INV_VIST_FORM_n.xls file with the same number.
At first I thought I could solve the problem using the following:
#echo off
for /f "delims=: tokens=1*" %%A in (
'dir /b *.xls ^| findstr /n "^"'
) do ren "%%B" "TWN_CH_INV_VIST_FORM_%%A.xls.new"
ren *.txt.new *.
I use DIR /B to list the files, and pipe that result to FINDSTR to prefix each file name with a line number, followed by a colon.
I then use FOR /F to iterate and parse the results into the number and the file name. FOR /F buffers the entire result before iterating, so I don't need to worry about renaming the same file twice.
I first give the renamed files a .xls.new "extension", just in case your directory already has files that meet the TWN_CH_INV_VIST_FORM_n.xls pattern. You don't want any name collisions. The final REN command then simply removes the .new extension to leave the desired .xls.
BUT, I just noticed that the original file names have lots of weird characters that could involve unicode that is not in the current code page. FOR /F does not play well with unicode.
There is one other minor issue in that the above does not pad the number to a fixed width. (this could have been solved easily enough)
So at this point it is time to break out my JREN.BAT regular expression renaming utility. It is pure script (hybrid batch / JScript) that runs natively on any Windows machine from XP onward. It has a built in facility to incorporate a fixed width incrementing number in the new name, and it works fine with unicode. I still temporarily give the new name the ".xls.new" extension to avoid any name collisions.
#echo off
call jren "^.*" "'TWN_CH_INV_VIST_FORM_'+$n+'.xls.new'" /j /npad 3 /fm *.xls
ren *.xls.new *.
I chose to pad the incrementing number to 3 digits instead of 2 because the OP said there could be 500 files.
Full documentation for JREN.BAT is available from the command line via jren /?, or jren /?? if you want paged output.

Resources