New user to alt.msdos.batch. Not new to batch files, just sadly
haven't really used them in a VERY long time. In my older age I think
I am getting senile and can't remember anything. Either that, or I am
getting senile and can't remember anything...
Anyway, what I have is a very large collection of fonts. I wrote a
generic batch file that sorts my files based on the first 2 characters
of the file name into the appropriately named folders.
The only extensions used are .TTF, .OTF and .TTC
My directory structure is as follows:
D:\Fonts\A\a0
\aa
\ab
\ac
.
.
.
etc...
For example, let's say i have the following existing files:
D:\Fonts\a\aa
aafont1.ttf
aafont2.ttf
aafont3.ttf
etc.
To make an "update" to my font collection, i would prefer that files
that do NOT exist get moved to another folder, let's call it
"D:\Fonts\Update".
Assume I now get the following new collection of fonts:
aafont3.ttf
aafont4.ttf
Obviously, aafont3.ttf already exists. i would prefer that that font
be moved to a folder called D:\Fonts\Dupes as an example.
Since aafont4.ttf is new and not already existing, i would like to
move that to a folder called "update".
is there simple way to have the batch file automatically go thru
folders and their sub-dirs and do this work for me?
I would love to try and do this myself, and certainly not asking
anyone to do the work for me, but would really appreciate some
guidance or tips and maybe a few snippets of sample code.
If it matters I am unfortuantely using Windows Vista.
I don't understrand why XCOPY doesn't have an switch to just ignore
existing files (or do something with them.)
HUGE thanks in advance for any help!
I hope this explanation was clear!
FL
P.S. I forgot to mention one thing. Some of the fonts have an
ampersand in the second position, i.e. a&font.ttf. How in the world
can i move that? it always give me errors. I tried googling teh heck
out of that question in every possible way i can think of... Thanks
again...
I think you really need to clarify what it is that you WANT to do.
You say that you want to move NEW files to D:\Fonts\Update and others to
D:\Fonts\Dupes
Why move to ...update? Shouldn't you move these to D:\fonts\first2\second1\
?
Next question is duplicates. What is really meant by "duplicate?"
We can have duplicate by NAME - where the files may be identical, or may be
an update or may be different entirely, if two entirely different fonts (but
equally, graphics, etc.) are encountered. We could also have the same
CONTENT in two completely different names...
I'd suggest it would not be a good idea to REPLACE any existing content;
files that are IDENTICAL could be deleted from the update-source and others
transferred to ...update for later manual examination.
And if you're running on D: then you can MOVE the file, otherwise you'd
probably be better off COPYing and DELeting.
So - to the mechanics, and thanks for choosing to buy the toolkit rather
than a custom package.
We have a question of approach. You're aware of the problems presented by
"&" and other characters (group venacular being 'poison' characters)
A solution (perhaps not perfect) is to sneak up on the processor by leaving
required strings in the metavariables (loop-control variables) - that way,
the parser doesn't get the chance to poke its little nose in...
for /f "delims=" %%i in (file) do echo "%%i"
is the general approach, where FILE may be 'some_command parameters'
(including the single-quotes) to use the output of some_command in place of
a file.
echo of course can be any command. %%i is quoted to form ONE token otherwise
any spaces (commas, semicolons...) in %%i would appear as separators for
whatever command ECHO is replaced with.
You can also use %%~zi, %%~xi, %%~ni etc for the size, extension of, name of
the file "%%i" - see
FOR /?
from the prompt for documentation (or read other threads here or
alt.msdos.batch.nt)
Your application would suggest a command such as
DIR /S /B /A-D *.ttf *.otf *.ttc
as a starting point.
You'd need to EXCLUDE D:\FONT\ from your scan, of course. Just in case you
ran it on D:
DIR /S /B /A-D *.ttf *.otf *.ttc | find /i /v "D:\FONT\"
would appear to fit the bill here - but if that's the command in parentheses
in a FOR /F statement, you'd need to escape the pipe with a caret (^)
Beyond that - substringing is relatively easy: %var:~start,length% will do
that - but since you can't substring a metavariable, you have to assign the
metavariable to a standard environment variable and substring THAT using a[n
internal] subroutine.
See
SET /?
for substringing documentation
Downfall there is that you then need to use the substrings in the context of
the metavariable, so you must invoke DELAYEDEXPANSION mode (and hence
SETLOCAL) which brings "!" into the fold of poison characters...
So....overall, I'd not try that approach directly.
What I would do is to use
DIR /S /B /A-D *.ttf *.otf *.ttc | find /i /v "D:\FONT\" >filename
which should generate a file with contents
C:\somedir\filename.ttf
then use SED or g(awk) to process this into the format
C:\somedir\filename.ttf:f:fi
where F and FI are the first, first2 letters of the filename. Colons used as
field separators because they will NEVER appear in a filename; we know about
the drivename so we appear to have 4 fields, separated by colons: drive,
path-to-filename,first-letter,first-two-letters
(Google for SED GAWK or AWK)
Once this format has been produced, the batch line
for /f "tokens=1-4delims=:" %%i in (processedfilename) do ECHO
%%i+%%j+%%k+%%l+%%~nxj+%%i%%j+
might be a start-point (just showing some combinations, separated by "+" for
clarity)
Your DO clause could then be
... do (
MD "D:\FONT\%%k" 2>nul
MD "D:\FONT\%%k\%%l" 2>nul
if exist "D:\FONT\%%k\%%l\%%~nxj" (ECHO %%~nxj exists) else (ECHO %%~nxj is
new)
)
- modify to suit, replacing ECHO... with commands to move, copy and delete
as appropriate...
I think Billious covered this but to point it out you can enclose the
name in double quotes.
EG
copy /b "c:\path\font&name.ttf" "d:\destination\path\"
--
Regards,
Mic
Thanks for those replies both of you... Great tips... And @Billious
- i thought i did clarify. Sorry.
I just want to sort files:
1. copy "new" files that don't exist to a folder called "update" or
something simlar by making sure that file doesn't already exist.
2. move files that DO already exist into a folder called "duplicates"
so they don't get overwritten.
thanks again
> Thanks for those replies both of you... Great tips... And @Billious
> - i thought i did clarify. Sorry.
>
> I just want to sort files:
>
> 1. copy "new" files that don't exist to a folder called "update" or
> something simlar by making sure that file doesn't already exist.
>
> 2. move files that DO already exist into a folder called "duplicates"
> so they don't get overwritten.
So you have:
D:\Fonts\
D:\Fonts\Update
D:\Fonts\Dupes
and you get a new collection of font files. If this new collection of
fonts is large and spanning many subfolders then you can get
A) several new font files
B) several new duplicates
* So how do you want to handle multiple duplicates of the same filename?
I can foresee that several copies of aafont3.ttf can be stored as
aafont3.0001.ttf
aafont3.0002.ttf
aafont3.0003.ttf
or do you want to put them in numbered folders?
--
Regards,
Mic
So you don't need to work out the FINAL destination directory then.
In that case, I'd suggest
1/ create a text file containing a filelist of your FONTS subtree, say
DIR /S /B /A-D D:\fonts >existing.txt
2/ For each filename (%%i) in your source of files, execute
FINDSTR /E /C:"\%%~nxi" existing.txt >nul
IF ERRORLEVEL 1 (move to new) else (move to update)
Which should select the destination, NEW or UPDATE as appropriate by
matching on whether the string "\filename" appears at the END of any line in
existing.txt
TRAP 1:
It is possible that a filename in your SOURCE may not match the LONG
filename present in your existing but may match the SHORT filename (possibly
of an unrelated file)
SO I'd use
FOR /F "delims=" %%i in ( ' dir /s/b/a-d D:\fonts ' ) do (
>>existing.txt echo %%i
>>existing.txt echo %%~si
)
Which should generate TWO lines per file in you FONTS tree, one with the
LONG filename and one with the SHORT. If the file does not have a shortname,
its name will simply appear twice in the list, which is of no consequence
since it is the mere PRESENCE of the "\filename" string that is important.
There is supposed to be some problem with the ~s operator, but I've never
been able to get a handle on what the nature of the problem is or how and
when it manifests itself, nor have I had problems with ~s myself.
Second trap:
Your MOVE (or COPY/DEL) may fail if there is a matching filename (long or
short) already in your destination directory.
IF EXIST "D:\Destinationdirectory\%%~nxi" (
>>errorfile echo DUP error moving "%%i"
) else (
actually execute your copy/delete or move
)
would seem to be applicable here...
I tested this and it works per the above.
It checks every existing font file for every new font, so it will
probably be quite slow.
It could be optimised somewhat by checking for your disk structure and
only checking the necessary folders - but see how slow this is in practice.
What it does is check every file in the current directory, including
subdirectories, (so this batch should be called from the PATH) and then
dynamically checks the d:\font tree for a file of the same name.
If it finds a match it will then figure out which incrementing number to
add to the filename and move it to the dupes folder with that name.
If there is no match then it will go into the update folder.
@echo off
md "D:\Fonts\Update\" 2>nul
md "D:\Fonts\Dupes\" 2>nul
for /f "delims=" %%a in ('dir /a:-d /o:n /b /s') do (
for /f "delims=" %%b in ('dir "d:\fonts" /a:-d /o:n /b /s') do (
echo "%%~nxa"
if /i "%%~nxa"=="%%~nxb" call :renum "%%a"
)
if exist "%%a" move "%%a" "D:\Fonts\Update\"
)
pause
goto :EOF
:renum
set c=10000
:loop
set /a c=c+1
set num=%c:~-4%
if exist "D:\Fonts\Dupes\%~n1.%num%%~x1" goto :loop
if exist %1 move %1 "D:\Fonts\Dupes\%~n1.%num%%~x1"
If I change this line
if /i "%%~nxa"=="%%~nxb" call :renum "%%a"
to this then it should be appreciably faster
if exist "%%a" if /i "%%~nxa"=="%%~nxb" call :renum "%%a"
So try this code on some test files:
@echo off
md "D:\Fonts\Update\" 2>nul
md "D:\Fonts\Dupes\" 2>nul
for /f "delims=" %%a in ('dir /a:-d /o:n /b /s') do (
for /f "delims=" %%b in ('dir "d:\fonts" /a:-d /o:n /b /s') do (
echo "%%~nxa"
if exist "%%a" if /i "%%~nxa"=="%%~nxb" call :renum "%%a"
)
if exist "%%a" move "%%a" "D:\Fonts\Update\"
)
pause
goto :EOF
:renum
set c=10000
:loop
set /a c=c+1
set num=%c:~-4%
if exist "D:\Fonts\Dupes\%~n1.%num%%~x1" goto :loop
if exist %1 move %1 "D:\Fonts\Dupes\%~n1.%num%%~x1"
--
Regards,
Mic
Did you forget to return and update this thread too? :)
--
Regards,
Mic
Thanks for the AWESOME replies and AMAZING code guys... Sorry
sometimes life takes over. Lost my business after 16 years over the
summer and trying to find work, you know how it is...
For the duplicate files
x(1).ttf
x(2).ttf
etc.,
they can _all_ go to the dupe folder. No need to need to go crazy
with those.
Love the code for checking for the existing files - and i don't care
how long it takes - the fact that you actually did this for me is more
than I could ask for!
I just got back from a crapola couple day gig and will try your code
as soon as a can - within the next day or two...
Thank you agan you guys rock!