Tutorial on Basic Windows 2000 DOS
This Section Will Cover
- 00. What a file is under win enviroment
- 01. What a variable is in %win2k% batch and how to create them.
- 02. What echo echo. @echo off does.
- 03. What operators like > and >> and | do.
- 04. What a ::comment is.
- 05. What & does and how to use it &::creatively.
- 06. What 'DIR' and 'SORT' is and does
- 07. What a * and a ? mean to the DOS shell.
- 08. What GOTO _is when used with :_labels, also using PING to create a delay.
- 09. What if "statements"=="are and what they do".
- 10. What a basic "for" loop is/does.
- 11. How to use low interger values with variables.
- 12. How to parse strings into substrings.
- 13. How to echo non-echoable characters.
- 14. How to pass %arguments to a .bat file.
- 15. Summary
Ok, the FOR loop. Although this is an extremely primitive FOR loop
that win2k has, it can be
very daunting to understand. But once you've got it, which might take
time, you'll look back and say
"Duh, that's simple". If you've never done anything like a
FOR loop, you might be better off. I was doing FOR loops in
C/C++ before in win2k .bat and I was like "What?!?!". I couldn't
make heads or tails of it to
be honest. If you know C, or done scripting on a unix system, what you're
about to see is goofy.
If not, well this is a good break in because the FOR loops in C or in
bash or whatever are much
easier, flexible, logical, and A LOT more free in terms of what you can
do. It's not really the FOR
loop that is goofy, its the damn shell that limits certain basic things. Like
there is no escape
character. An escape character only makes sense. What this is, is a
character that escapes the
system's way of handling a character and lets you use the character as a
literal. What i mean by
this is that, you know when you did DIR /B *.mp? Well, what if you
want to use the characters
of * or ?, what are you to do then? In programming languages
and all shells besides win shells you can
usually preceed the character with a \ to represent you want to use the character as it is without
the shell's default method. \* or \? would let you search
for those characters themselves. But you
see, in windows you cant use those characters in file names. So the shell
automatically thinks you
don't need to process those characters PERIOD for ANYTHING you want to
do...which is downright, I
hate to use this word but it fits, stupid. I will cover a lengthy, but
workable, way of getting around
this stupid limitation later on. Ok let's start.
Basically a FOR loop goes roughly like this...
FOR variable IN (whatever) DO this_with variable
FOR %%i IN (*.*) DO echo %%i
NOTE: In .bat files you have to use %%. If you were typing this in live from the shell you would use 1 %
The reason is yet again sort of goofy. It's because the % is used to reference variables. Like
echo %fooy%. The system sees that fooy is surrounded by %'s so it knows to treat it as a
variable and remove the %'s and reference the value. Strangely
though, when you're typing in live
commands not from a .bat but the shell itself, you still only use 1 % around variables. Got me,
maybe I don't understand it right but it all seems goofy to
me.
Ok, make another .bat file and put the below in it....
@echo off
FOR %%i IN (*.*) DO echo %%i
echo.
echo Press [ENTER] to exit
pause >nul
What you should see is a echo of all the files in the directory where the .bat is in your system.
What this FOR loop will do is take all the variables in (*.*) and echo each one out. Now %%i
is NOT all variables, in fact %%i is the last variable it found. (*.*) lists all files, same thing if you
did DIR /B /A-D. Remember that /AD list all the
directories, well when you preceed the D with a
- that means NOT. So it lists everything that is NOT a directory.
But /A-D is a DIR switch, let's get
back to FOR loop.
It goes through the loop as long as a file exists. %%i becomes the
first file it finds. Then when it goes
again %%i becomes the next file it finds, so on and so on until it finds no more files. So when the
loop finally exits, %%i was the last file it found, not all the files it found. You can change this,
with the cmd.exe in a manner where you could use %%i as if it was all files, but that goes beyond the
scope of this tutorial because the easiest way to make this happen is by altering a registry key, and that is not what this
is about.
What lies within the ( ) in the FOR loop can pretty much be
One of three things. But it's best understood as four
things.
1. A set of files�������(*.mp?)
2. A command������������(DIR /B /A-D)
3. A string of text�����("Hello Batch!")
4. A set of arguments���(%1 %2 %3 %4 %5 %6 %7 %8 %9)
In the above, number 4. the arguments can actually be any of the first
three numbers depending on what the
arguments are themselves. What I mean by this is that the syntax will
remain the same, as in %1 %2
etc...but what those arguments are can vary. Each argument can be text, a file, or a command, but you
probably will never see arguments being anything other than files. Due to the fact that it can be tricky
to get white spaces (spaces and tabs are known as white spaces) and certain characters into arguments.
Now when you pass in arguments, you dont use %1 %2 ... but when you read the arguments in a script after
passing them into it, you use this method.
Ok so we now know how to use DIR (or do we?).
OK take the cdrom drive letter in your system, E: , F: or whatever it is, put a cd/dvd in the drive with files on it, and
in a DOS shell type DIR /B E: or whatever you drive letter is.
You should see a listing of all the directories and files in the root of
the cd, remember root is the
top most directory, like C:\ is root to your HDD. If you want to see what is in the subdirectories of
of the directories on the cd, add the /S switch. DIR /B /S
Ok now that you know what that does, let's explore the options of the FOR itself. Type FOR /?
in a DOS window to see the options it has.
Ok what you see is pretty lengthy, but not to worry, i'll make it simple for what we are going to use.
FOR /F - means you want to use a file as input
FOR /F "usebackq tokens=* delims=_" - means you want to use a file as input. usebakq means you want to enforce
the routines more or less. And
tokens and delims means, well let's
talk about that...
Tokens and Delims go hand-in-hand. Delims is short for Deliminators. A deliminator is something that
breaks someting into Tokens. For example, lets say you have the below string...
Hello_my_handle_is_Space_Between
Now the above is on string of text right? (a string means just a line of text, no hidden meaning).
Ok let's say we want to get each word of the above string into seperate words, deliminators will do that
for us. If we set our deliminator to equal an underscore delims=_
then the tokens get broken up like
this...
Token 1: Hello
Token 2: my
Token 3: handle
Token 4: is
Token 5: Space
Token 6: Between
With a delim of _ we get 6 tokens out of the string
Hello_my_handle_is_Space_Between. I hope you understand this, this
is as simple as I can make that :-).
Ok notice the tokens=* in "usebackq tokens=* delims=_". Ok
now tokens=* means I'm going to get all tokens that
are in the string. Now by default, delims are set to white spaces (spaces
and tabs), so I manaully set
the delims=_ and now the only delim is a _. However, since I set
tokens=*, I really don't need a delim at
all. Since i'm going to get all tokens, what does it matter what my delim
is? It doesn't. I'm getting all
tokens regardless of what the delim may be. So if we use tokens=* we can just use "usebackq tokens=*"
and nothing more. However, since deliminators are by default spaces and
tabs, it won't break the string up into 6 tokens.
Since we didn't specify a delims=_ it's going to use spaces and
tabs, thus resulting in the same exact string of
Hello_my_handle_is_Space_Between
NOTE: I use usebackq because I'm used to using it, you can do it without
usebackq, but it can possibly be
better to usebackq regardless. So I suggest always to use it.
However when you usebackq, you have
to use different characters. Like backqoute, that is the key to the
left of the number 1 and above
the Tab key. It is on the same key as ~. When using usebackq you use a
backqoute to surrond
a command.
Here is part of what FOR /? brings up in a shell...
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
or, if usebackq option present:
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
FOR /F ["options"] %variable IN ('string') DO command [command-parameters]
FOR /F ["options"] %variable IN (`command`) DO command [command-parameters]
Ok, here is the FOR loop that can catalog a cd/dvd contents for you. Copy this and put it in your .bat and run it.
Make sure your Drive letter is correct, im using E:\ for this example because it is my cdrom drive letter.
@echo off
FOR /F "usebackq tokens=*" %%i IN (`DIR /ON /B E:\`) DO ECHO %%i
pause >nul
Ok so that does nothing different than DIR /ON /B E:\ at all, same exact thing, however we can add
things to this echo out...like variables.
A nice way to get variables to add to this FOR loop would be to use SET /P. OK, SET /P actually halts the
system and waits for you to type in something and hit the [ENTER] key.
Ok now, find out the drive letter in your system and assign it to a variable. Change your script to look
like the below script and run it after you have assigned the correct drive
letter. I'm using E:\ still.
@echo off
DIR /B *.bat | FIND /I ".bat"&::using the /I switch with FIND makes it case insensitive
SET CDROM=E:\
echo This pause is just so you can see that the pipe method
echo worked with DIR and FIND. More help on FIND with FIND /?
echo.
echo Press [ENTER] to continue...
pause >nul
:_loopa
CLS
echo.
echo.
echo Enter something now to prefix the output of your cdrom listing.
echo.
echo.
SET prefix=&:: Notice I'm making sure prefix is unset to nothing at all
SET /P prefix=
IF "%prefix%"=="" GOTO _loopa
echo.
echo.
SET suffix=&::
:_loopb
SET /P suffix=Enter a suffix for the output now: &::suffix's prompt msg, not its value, nor ever will be
IF "%suffix%"=="" GOTO _loopb
echo.
FOR /F "usebackq tokens=*" %%i IN (`DIR /ON /B %CDROM%`) DO ECHO %prefix% -: %%i :- %suffix%
echo.
echo Press [ENTER] to exit
pause >nul
In the above you notice that in SET /P suffix=Enter a suffix for the output now: and might
be thinking that its value is already set. Well it's not. When you use SET /P you have the option
of setting the prompt for it. This is not the value of suffix at all, and if you just hit
enter without typing anything in then the variable has no value at all. At no point is the prompt
going to be assigned to the variable. This prompt rarely comes in handy,
but I found uses for it
a couple times especially when how many lines can be displayed on the screen
at one time came into
concern.
Also notice that I did SET prefix=&:: Notice I'm... just in case
the variable prefix was already assigned. By doing
this I assure myself of a loop if nothing is entered. If nothing is
entered it performs GOTO _loopa
Since I can not really do a IF statement on the contents of either
prefix or suffix without knowing what they are, I SET
them
back to nothing. In a bigger script knowing exactly what a value is, to
peform such a loop would be
hard and tiring. suffix or prefix could have been anything
before, so setting them back to "". let me
know exactly what the value was.
About the label, the label itself, should have a colon : in front of it, like :_loopb If you want
to jump to that point you will have to use GOTO _loopb Notice
there is no colon in front of the label
name here. By rule the actual label is :_loopb but to GOTO it
you don't use the colon :. Now in win2k
you can use the colon. ie GOTO :_loopb, however this won't work on
older platforms. Also, if you ever
want to immediately exit a script with GOTO, there is a built-in
label
of :EXIT and :EOF. You're going to
want to use :EXIT to exit out of a script, :EOF does the same
thing but it goes to the End Of File.
So to immeditely exit out of a script you can do GOTO :EXIT :EOF and :EXIT might be
the same exact thing. I use :EXIT because I'm used to it. Both of
them are for win2k and later, not anything
older.
If you wanted to use the actual code above to catalog, you could just put >> cat_file.txt on the end of
the FOR loop and it would output everything to that file. However,
I would suggest using a variable
for the file name, like the below will output to a filename in the "my catalogs" directory...
@echo off
SET FILENAME="c:\my catalogs\cdvd cat.txt"
SET CDROM=E:\
MKDIR "C:\my catalogs" 2> nul
DIR /B *.bat | FIND /I ".bat"&::using the /I switch with FIND makes it case insensitive
echo This pause is just so you can see that the pipe method
echo worked with DIR and FIND. More help on FIND with FINE /?
echo.
echo Press a Key to continue
pause >nul
:_loopa
CLS
echo.
echo.
echo Enter something now to prefix the output of your cdrom listing.
echo.
echo.
SET prefix=&::
SET /P prefix=
IF "%prefix%"=="" GOTO _loopa
echo.
echo.
SET suffix=&::
:_loopb
SET /P suffix=Enter a suffix for the output now: &::suffix's prompt msg, not its value, nor ever will be
IF "%suffix%"=="" GOTO _loopb
echo.
FOR /F "usebackq tokens=*" %%i IN (`DIR /ON /B %CDROM%`) DO ECHO %prefix% -: %%i :- %suffix% >> %FILENAME%
echo.
echo Press [ENTER] to exit
pause >nul
You might notice that when I declared my variable for the cdrom and for
the filename, I used all capitals.
This is good practice for variables that are fixed and whose values will
not change. These variables will
be CONSTANTS so by making them all UPPERCASE they are easier to find/alter
if you have to debug, fix, or expand
your code. Another reason they are all UPPERCASE is because by changing them
you change them everywhere
throughout your script. So just by changing this one variable, you might
drastically change your entire
script for better or for worse.
Also if you're going to use spaces in your file names and directories (I
surely hope you don't) you must
surround them in "'s. This goes for directories too. Even if you don't
use spaces it's good practice in win2k .bat
to still do it.
Also you see another command MKDIR This makes a directory named
"C:\my catalogs". Remember if you're
going to use spaces in filenames and/or directories you must use "'s. Now if the directory exists, it will give
an error msg, but nothing bad will happen. However notice the 2>.
You can put numbers before output >'s
that represent the type of msg. The two most useful are 1> which
basically is the samething as >, and the other
is 2>nul This will redirect the error msg to nul. 2> is for errors more or less. Anyways, when you do MKDIR
to create a directory, and the directory already exists, you may see a error msg unless you redirect the
error output 2> to nul. By good practice anything you
don't want seen by the user redirect it to >nul.
If you're trying to redirect something to >nul and you see a error
msg put a 2 infront of the >. It doesnt
work always but alot of times it does.
Click here to continue
|