Hidden features of Windows batch files
Asked Answered
D

91

232

What are some of the lesser know, but important and useful features of Windows batch files?

Guidelines:

  • One feature per answer
  • Give both a short description of the feature and an example, not just a link to documentation
  • Limit answers to native funtionality, i.e., does not require additional software, like the Windows Resource Kit

Clarification: We refer here to scripts that are processed by cmd.exe, which is the default on WinNT variants.

(See also: Windows batch files: .bat vs .cmd?)

Drolet answered 29/10, 2008 at 0:34 Comment(0)
D
185

Line continuation:

call C:\WINDOWS\system32\ntbackup.exe ^
    backup ^
    /V:yes ^
    /R:no ^
    /RS:no ^
    /HC:off ^
    /M normal ^
    /L:s ^
    @daily.bks ^
    /F daily.bkf
Drolet answered 29/10, 2008 at 0:34 Comment(4)
The ^ is really a quote char. Using it, you can quote < and > so that they do not redirect output. The ^ at the end of a line also allows line continuation.Canaille
Could you please explain this little scriptlet?Window
@furtelwart: This is the same as if you wrote all into one single line: call C:\WINDOWS\system32\ntbackup.exe backup /V:yes /R:no /RS:no /HC:off /M normal /L:s @daily.bks /F daily.bkf. And to understand all the parameters of that line, simply run C:\WINDOWS\system32\ntbackup.exe /?.Sinfonietta
The in depth discussion about this topic, at long commands split over multiple linesCastroprauxel
J
150
PUSHD path

Takes you to the directory specified by path.

POPD

Takes you back to the directory you "pushed" from.

Jameson answered 29/10, 2008 at 0:34 Comment(7)
This also works as a full stack, so you can push many directories onto the stack, and then keep on popping to get back where you were.Wurth
Run 'cmd.exe' then type 'help', then type 'help pushd' or 'pushd /?'.Dandrea
If you pushd to a UNC path, it will automatically map a drive for you and the popd will unmap it.Exclude
in csh, if I recall, a pushd with no arg just cycled the stack. But that doesn't work on cmd.exe, does it?Canaille
Unlike cd, you can also use pushd to switch between directories on different drives. (If you're in C:\Windows and want to be in D:\Games, then pushd D:\Games takes you there instead of typing D: and cd D:\Games.)Kamchatka
@Jameson why did you roll back previous edit, isn't the UNC path working?Colenecoleopteran
@CharlesB: It's redundant. Look at Ferruccio's comment that explains that functionality. It has 77 up votes and it's bright orange. Also, I think people should know that he pointed that out. I wasn't aware of it when I posted this.Jameson
S
109

Not sure how useful this would be in a batch file, but it's a very convenient command to use in the command prompt:

C:\some_directory> start .

This will open up Windows Explorer in the "some_directory" folder.

I have found this a great time-saver.

Samaritan answered 29/10, 2008 at 0:34 Comment(14)
well, I use it too. I have a "open.cmd" file in one of the PATH directories, and the only thing in that file is "@start ." ;)Lengthwise
'explorer' also does the same thing as 'start' C:\some_directory>explorer .Alecalecia
+1 Use it all the time :-) ... CD with tab completion in command prompt then pops up an explorer window with start . :-)Arrio
I prefer "C:\some_directory> explorer /e,." this will open explorer in Folder ViewBujumbura
I tend to type this as [ start "" . ] (brackets for clarity) because start is sometimes finicky about the first param being a title.Abaca
Is the reverse available -- navigate through explorer to a desired folder, then click something to open a command Window "in" that folder?Rhody
@Philip - There are various powertool utilities which allow this. Here's an example, but I haven't tried this particular software myself: petri.co.il/…Samaritan
I just type start. (No space.)Tung
If you happen to be on a Mac, open . does the same thing.Mortensen
@Philip: If you're on Vista or later, try Shift-Right-Click on a folder. You'll get a few new items in your context menu including "Open command window here".Kamchatka
start does way more than just open the current folder. You can pass it any file and it will open it with the configured viewer. Give it a URL and your default browser opens, etc...Kamchatka
explorer /select,"file" will open a window for the folder of the file and highlight the file (if the folder window wasn't already open)Temper
@RayVega In Windows 7, "explorer" does not open the current folder. At least not for Home Premium I'm using at the moment. Instead, it opens Libraries.Rees
@HalilÖzgür- Did you include the period (".") after the explorer command? It needs that to open the current directory. C:\some_directory>explorer .Alecalecia
D
87

I have always found it difficult to read comments that are marked by a keyword on each line:

REM blah blah blah

Easier to read:

:: blah blah blah
Drolet answered 29/10, 2008 at 0:34 Comment(4)
I heard :: is more efficient than REM because REM attempts to do environment variable expansion on the stuff that occurs after it, but :: does not.Osborne
In fact, :: is just a label with a funny name; therefor, :: will not work if you use it inside a block (in parentheses) since labels are not allowed there either. REM works there of course.Dicotyledon
Note though that rem is a documented keyword while :: is just an implementation detail. While it's unlikely that :: will stop working it's generally advisable not to rely on undocumented behavior.Alewife
You can even use goto : to jump to the label. :-) and goto -) will also work.Xylol
D
79

Variable substrings:

> set str=0123456789
> echo %str:~0,5%
01234
> echo %str:~-5,5%
56789
> echo %str:~3,-3%
3456
Drolet answered 29/10, 2008 at 0:34 Comment(4)
@furtelwart sounds like that could be the batch mottoStabile
this great for formatting dates (however the problem I found was that vista/7 and xp output DATE differently)Sciolism
Note that unfortunately, this cannot be combined with the local variables of FOR loops (for %a in ...) since they don't require the closing percentage sign as does environment variables; you must first assign them to an environment variable (using delayed expansion!) and then extract a substring.Ungulate
This is an inevitable ugly if you want to do something with dates (e.g. backup file names). After witnessing the general ugliness of Windows command line, I see why Windows is mostly point & click :) Though they say that the new PowerShell is better.Rees
M
72

The FOR command! While I hate writing batch files, I'm thankful for it.

FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k

would parse each line in myfile.txt, ignoring lines that begin with a semicolon, passing the 2nd and 3rd token from each line to the for body, with tokens delimited by commas and/or spaces. Notice the for body statements reference %i to get the 2nd token, %j to get the 3rd token, and %k to get all remaining tokens after the 3rd.

You can also use this to iterate over directories, directory contents, etc...

Motoring answered 29/10, 2008 at 0:34 Comment(5)
I've found the batch files' FOR loops limited and terrible to write, but they are useful sometimes.Tiu
Excuse my bafflement, but how on earth is this underused? I think if you don't know FOR loops, you don't know batch scripting.Tung
Underused or not, it is torture. (Some would argue a necessary evil.)Homologize
I had to use it a few times and the person who made up this syntax should be fired. From a cannon. Into the sun. It is THAT bad.Cornelia
@CodingWithStyle: Every time I need to write a for loop in a batch file, the script becomes a bash launcher and rewrite the script in bash (or python) instead : )Kamchatka
F
60

Rather than litter a script with REM or :: lines, I do the following at the top of each script:

@echo OFF
goto :START

Description of the script.

Usage:
   myscript -parm1|parm2 > result.txt

:START

Note how you can use the pipe and redirection characters without escaping them.

Freya answered 29/10, 2008 at 0:34 Comment(2)
Would be even cooler if you checked the %1 for "/?" and then you could echo that section as help text.Catricecatrina
Hmm, literate batch programming ?!Gallipot
F
54

The path (with drive) where the script is : ~dp0

set BAT_HOME=%~dp0
echo %BAT_HOME%
cd %BAT_HOME%
Frias answered 29/10, 2008 at 0:34 Comment(6)
I usually use %CD% for this. Maybe it is not available in all DOS shell versions?Stylize
%CD% is the current directory while %~dp0 is the directory where the running script is located.Frias
Also, I don't think %CD% existed before...XP, maybe. I know some older versions of Windows don't have it.Ajani
You should use cd /d %BAT_HOME% instead, if the bat is in another drive. If I remember correctly, this wont work with older DOSes, though.Erek
cd or pushd %BATH_HOME% will not work if you run a batch on a network path.Guaiacol
When using %~dp0 in a command such as CD or COPY, you should enclose it in a pair of double quotes, in case the path contains a space. Same for environment variables based on %~dp0. E.G. in this answer's sample code, the third line should be cd /d "%BAT_HOME%"Bequeath
C
49

The %~dp0 piece was mentioned already, but there is actually more to it: the character(s) after the ~ define the information that is extracted.
No letter result in the return of the patch file name
d - returns the drive letter
p - returns the path
s - returns the short path
x - returns the file extension
So if you execute the script test.bat below from the c:\Temp\long dir name\ folder,

@echo off
echo %0
echo %~d0
echo %~p0
echo %~dp0
echo %~x0
echo %~s0
echo %~sp0

you get the following output

test
c:
\Temp\long dir name\
c:\Temp\long dir name\
.bat
c:\Temp\LONGDI~1\test.bat
\Temp\LONGDI~1\

And if a parameter is passed into your script as in
test c:\temp\mysrc\test.cpp
the same manipulations can be done with the %1 variable.

But the result of the expansion of %0 depends on the location!
At the "top level" of the batch it expands to the current batch filename.
In a function (call), it expands to the function name.

@echo off
echo %0
call :test
goto :eof

:test
echo %0
echo %~0
echo %~n0

The output is (the batchfile is started with myBatch.bat )

myBatch.bat
:test
:test
myBatch
Clockmaker answered 29/10, 2008 at 0:34 Comment(0)
E
43

By using CALL, EXIT /B, SETLOCAL & ENDLOCAL you can implement subroutines with local variables.

example:

@echo off

set x=xxxxx
call :sub 10
echo %x%
exit /b

:sub
setlocal
set /a x=%1 + 1
echo %x%
endlocal
exit /b

This will print

11
xxxxx

even though :sub modifies x.

Exclude answered 29/10, 2008 at 0:34 Comment(6)
You should rather use goto :eof instead of exit /b, does the same thing but is the more standard way to do it.Chimborazo
There's a standard for this? O_oLengthwise
It's not "more standard", it's more common because most people don't know about the /b option of exit.Exclude
My mistake. I thought you meant explicitly defining an :eof label and doing a goto to that. I did not realize there is an implicit :eof label at the end of every batch file.Exclude
However, if you want a subroutine to set an errorlevel, you will need to use exit /b. For example: exit /b 3Drolet
I've found it best to use "exit /B" instead of "goto :eof" to return from a subroutine, "goto :eof" has the problem that you may return an error code when you want to swallow it. For example if you use "if exist someFile echo it's here", this will set the errorlevel if someFile doesn't exist, but that's not wrong, and isn't an error code that you'd want to return (which is what "goto :eof" would do).Osborne
D
42

Sneaky trick to wait N seconds (not part of cmd.exe but isn't extra software since it comes with Windows), see the ping line. You need N+1 pings since the first ping goes out without a delay.

    echo %time%
    call :waitfor 5
    echo %time%
    goto :eof
:waitfor
    setlocal
    set /a "t = %1 + 1"
    >nul ping 127.0.0.1 -n %t%
    endlocal
    goto :eof
Dandrea answered 29/10, 2008 at 0:34 Comment(3)
Even better is to put this in a file like sleep.bat to save you the trouble of rewriting it over and over.Moat
...and put the sleep.bat in some directory in the PATH environment variableGannie
I'm against putting this outside, makes the less portable... across Windows systems.Scorn
D
37

Escaping the "plumbing":

echo ^| ^< ^> ^& ^\ ^^
Drolet answered 29/10, 2008 at 0:34 Comment(4)
I'll bet the DOS escape character is not well known. Good one.Hardworking
Ah, that'd explain why it's the line continuation operator as well -- it escapes the newline, just like \ in bash...Instrumentalist
@leander: Yes, but it only can escape the LF (and not the CR), because all CRs are removed beforeCastroprauxel
So this is why using git on Windows to diff against the previous commit (HEAD^) is problematic.Manhood
D
31

Being able to run commands and process the output (like backticks of '$()' in bash).

for /f %i in ('dir /on /b *.jpg') do echo --^> %i

If there are spaces in filenames, use this:

for /f "tokens=*" %i in ('dir /on /b *.jpg') do echo --^> %i
Dandrea answered 29/10, 2008 at 0:34 Comment(3)
Doesn't work with filenames which has spaces in their names... This works: for /f "tokens=*" %i in ('dir /on /b *.jpg') do echo --^> %iLlywellyn
Good catch. Personally I think spaces in file names are evil hideous things from the depths of the ninth circle of Hell. But we should cater for them, I guess.Dandrea
That's the craziest syntax I've seen yet. Does it work if you made this backtick.bat and pass in the string?Kamchatka
C
30

Creating an empty file:

> copy nul filename.ext
Cavatina answered 29/10, 2008 at 0:34 Comment(4)
@devio: echo. puts an empty line. so the file wouldn't be empty!Lengthwise
I use type nul > filename.ext for that.Guaiacol
Nice I was wondering if there was a touch equivalent for a long time.Hydraulics
I’ve always used ren > blah.txtCrichton
G
28

To hide all output from a command redirect to >nul 2>&1.

For example, the some command line programs display output even if you redirect to >nul. But, if you redirect the output like the line below, all the output will be suppressed.

PSKILL NOTEPAD >nul 2>&1

EDIT: See Ignoring the output of a command for an explanation of how this works.

Goatsbeard answered 29/10, 2008 at 0:34 Comment(6)
Do you know how this works? What's the meaning of the 2>&1 bit?Osborne
The >nul redirects STDOUT to nul. The 2>&1 redirects STDERR to wherever STDOUT is pointing.Goatsbeard
Specifically, I think the 2>&1 is a "filehandle clone", setting STDERR to a clone of STDOUT. Putting it after the >NUL is important, because you want to clone STDOUT after it has been redirected, not before. (Please correct me if I'm wrong here.)Instrumentalist
For those of you wondering where PSKILL comes from, check out sysinternals.com. If you're on a Pro edition, you should have a native TSKILL command that's more or less the same.Tung
If you don't have pskill or tskill, most Windows systems I've used come with taskkill.Kamchatka
If you only wanted to hide the error output, you could do PSKILL NOTEPAD 2>nul. So 2>&1 means 2> (redirect error) &1 (to stdin as an input -- that's what the & is for). I tend to forget the order of the characters so that explanation should help remember why they're in that order.Kamchatka
D
25

The equivalent of the bash (and other shells)

echo -n Hello # or
echo Hello\\c

which outputs "Hello" without a trailing newline. A cmd hack to do this:

<nul set /p any-variable-name=Hello

set /p is a way to prompt the user for input. It emits the given string and then waits, (on the same line, i.e., no CRLF), for the user to type a response.

<nul simply pipes an empty response to the set /p command, so the net result is the emitted prompt string. (The variable used remains unchanged due to the empty reponse.)

Problems are: It's not possible to output a leading equal sign, and on Vista leading whitespace characters are removed, but not on XP.

Dandrea answered 29/10, 2008 at 0:34 Comment(0)
J
25
PAUSE

Stops execution and displays the following prompt:

Press any key to continue . . .

Useful if you want to run a batch by double-clicking it in Windows Explorer and want to actually see the output rather than just a flash of the command window.

Jameson answered 29/10, 2008 at 0:34 Comment(8)
I would hardly call this "underused" as I tag it on to the end of every script I write. Then again, it doesn't work so well when you want to have your IDE run the script and capture the output, as the IDE has no way to press enter for you usually...Warship
So you can't pipe something to the script then? Like the 'yes' of the unix world? (I'm just reading this thread out of curiousity -- I've got nothing to offer :p )Ossuary
One neat feature of "pause" is that if there's no terminal around to receive an "any key" (e.g. if your batch file is run from a system service), it detects this and just keeps going...Instrumentalist
+1 to Charlie Somerville, this is so known every game programmer's 'go.bat' used it back in the early 90s.Hathor
Instead of polluting all of your batch files (and making them annoying to use for CLI geeks), you could use Start / Run / then type 'cmd /k ' and the batch file name. OR change HKCR\batfile\shell\open\command default string to 'cmd /k "%1" %*'. OR make another batchfile which just runs '@cmd /k $*', put it on the desktop and drop your other batch files on it. There are lots of alternatives to PAUSE. Please consider them.Abaca
@gnud: you can still pipe to the script: echo.|batch-with-pause.bat will have the same effect as pressing the 'any-key'...Sinfonietta
Is there any way to detect in the script that it was started with a double-click vs. the command line?Dangelo
@Lance: not that I'm aware of.Jameson
H
18

Search and replace when setting environment variables:

> @set fname=%date:/=%

...removes the "/" from a date for use in timestamped file names.

and substrings too...

> @set dayofweek=%fname:~0,3%
Hindquarter answered 29/10, 2008 at 0:34 Comment(0)
D
17

Integer arithmetic:

> SET /A result=10/3 + 1
4
Drolet answered 29/10, 2008 at 0:34 Comment(4)
How long have SET got the ability to calculate? Windows XP?Arrio
If you are asking how big the values can be, I believe this is 32-bit. So +/- 2 billion.Drolet
I think the question was, how long has SET been able to calculate? Since Windows XP?Wipe
I thing CMD.EXE's SET has been able to calculate since NT 3.1 or so. It just took a long time for anyone to notice that CMD.EXE wasn't exactly the same as COMMAND.COM...Fugacity
L
16

Command separators:

cls & dir
copy a b && echo Success
copy a b || echo Failure

At the 2nd line, the command after && only runs if the first command is successful.

At the 3rd line, the command after || only runs if the first command failed.

Llywellyn answered 29/10, 2008 at 0:34 Comment(0)
R
15

You can chain if statements to get an effect like a short-circuiting boolean `and'.

if foo if bar baz
Revivalist answered 29/10, 2008 at 0:34 Comment(1)
This is really just a shortcut for nesting ifs: if foo ( if bar ( baz ) ) (Imagine newlines after the brackets.)Kamchatka
D
15

Output a blank line:

echo.
Dandrea answered 29/10, 2008 at 0:34 Comment(0)
E
14

if block structure:

if "%VS90COMNTOOLS%"=="" (
  echo: Visual Studio 2008 is not installed
  exit /b
)
Exclude answered 29/10, 2008 at 0:34 Comment(3)
As long as you're aware that variables will be expanded all in one go (without delayed expansion) - i.e. you can't sensibly use %ERRORLEVEL% in there.Supertonic
You also can't use labels there (which includes those :: style comments) because it will prematurely end the if statement.Tung
@Duncan: You shouldn't use the pseudo-variable %ERRORLEVEL% anyway; that's what if errorlevel <foo> is for. And that does in fact work in such blocks.Alewife
F
14

To quickly convert an Unicode text file (16bit/char) to a ASCII DOS file (8bit/char).

C:\> type unicodeencoded.txt > dosencoded.txt

as a bonus, if possible, characters are correctly mapped.

Frias answered 29/10, 2008 at 0:34 Comment(2)
That's an ANSI DOS file - ASCII is 7bit/char.Lanie
Lol, this one is an anti-pattern, this conversion is high likely to fail. The only 8 bit encoding supporting Unicode being the UTF-8 but thanks to M$ you cannot have the UTF-8 codepage set on Windows.Scorn
C
12

Doesn't provide much functionality, but you can use the title command for a couple of uses, like providing status on a long script in the task bar, or just to enhance user feedback.

@title Searching for ...
:: processing search
@title preparing search results
:: data processing
Clockmaker answered 29/10, 2008 at 0:34 Comment(2)
Interesting. Although thereafter you apparently lose the regular feature, which is to show the currently running command. Is there any way to reset that?Drolet
technet.microsoft.com/en-us/library/bb491017.aspx says it can be reset with "title" on its own, but this doesn't seem to work on Windows 7...Station
D
12

Delayed expansion of variables (with substrings thrown in for good measure):

    @echo off
    setlocal enableextensions enabledelayedexpansion
    set full=/u01/users/pax
:loop1
    if not "!full:~-1!" == "/" (
        set full2=!full:~-1!!full2!
        set full=!full:~,-1!
        goto :loop1
    )
    echo !full!
    endlocal
Dandrea answered 29/10, 2008 at 0:34 Comment(0)
C
11

Don't have an editor handy and need to create a batch file?

copy con test.bat

Just type away the commands, press enter for a new line. Press Ctrl-Z and Enter to close the file.

Clockmaker answered 29/10, 2008 at 0:34 Comment(0)
P
11

example of string subtraction on date and time to get file named "YYYY-MM-DD HH:MM:SS.txt"

echo test > "%date:~0,4%-%date:~5,2%-%date:~8,2% %time:~0,2%_%time:~3,2%_%time:~6,2%.txt"

I use color to indicate if my script end up successfully, failed, or need some input by changing color of text and background. It really helps when you have some machine in reach of your view but quite far away

color XY

where X and Y is hex value from 0 to F, where X - background, Y - text, when X = Y color will not change.

color Z

changes text color to 'Z' and sets black background, 'color 0' won't work

for names of colors call

color ?

Parlor answered 29/10, 2008 at 0:34 Comment(2)
edited; the _'s were interpreted as italics. Nice bit of code.Dram
@Duncan Smart: not true, also works in UK English (although technically it should be "colour", grrr)Catricecatrina
D
10

Total control over output with spacing and escape characters.:

echo.    ^<resourceDir^>/%basedir%/resources^</resourceDir^>
Dandrea answered 29/10, 2008 at 0:34 Comment(3)
How does that work? The dot demarcates the beginning of the text output?Drolet
"echo. x" will output "<space>x", "echo x" will only output "x". This allows leading spaces. In addition the "^" escape character will prevent cmd from thinking all those "<" and ">" characters are I/O redirection.Dandrea
echo( is better, because echo. creates a file search for a file named "echo" if this file exists the echo. fails, if not then internal echo is executed, but it is slower than echo(Castroprauxel
I
9

TheSoftwareJedi already mentioned the for command, but I'm going to mention it again as it is very powerful.

The following outputs the current date in the format YYYYMMDD, I use this when generating directories for backups.

for /f "tokens=2-4 delims=/- " %a in ('DATE/T') do echo %c%b%a
Insensate answered 29/10, 2008 at 0:34 Comment(3)
Surely DATE /T returns 29/10/2008 in Europe and 10/29/2008 in the US... so some localisation may be required! ;-)Reenareenforce
That's right! But you can abuse the date command to find out which date format is used.Insensate
It's excessive use of FOR, imo. I think I would just use %DATE:~10,4%%DATE:~4,2%%DATE:~7,2% for that rather than run a date command then parse it through for.Tung
R
8

You can use call to evaluate names later, leading to some useful properties.

call set SomeEnvVariable_%extension%=%%%somevalue%%%

Using call to set variables whose names depend on other variables. If used with some variable naming rules, you can emulate data collections like arrays or dictionaries by using careful naming rules. The triple %'s around somevalue are so it will evaluate to one variable name surrounded by single %'s after the call and before set is invoked. This means two %'s in a row escape down to a single % character, and then it will expand it again, so somevalue is effectively a name pointer.

call set TempVar=%%SomeEnvVariable_%extension%%%

Using it with a temp variable to retrieve the value, which you can then use in logic. This most useful when used in conjunction with delayed variable expansion.

To use this method properly, delayed variable expansion needs to be enabled. Because it is off by default, it is best to enable it within the script by putting this as one of the first instructions:

setlocal EnableDelayedExpansion
Recumbent answered 29/10, 2008 at 0:34 Comment(4)
You can also use delayed expansion using ! instead of % (with the right mixture, though). When dealing with arrays of data I frequently use things like "set foo=!array[%i%]!". The %i% gets expanded immediately while the stuff between ! will be expanded afterwards, using the value %i% had at that time.Alewife
Most PCs don't have delayed expansion enabled by default. If you need your variables global, you usually can't rely on delayed expansion to do the trick. Besides, there are times when you need more than one layer of delayed expansion, and this trick comes in handy then.Tung
True, this does need delayed expansion, but you can enable it within your script. I am updating my answer now to include that.Recumbent
AFAICT, either you use CMD /V:ON or SETLOCAL ENABLEDELAYEDEXPANSION to activate it within the script. Neither of these let you use it for globals (CMD sub-instantiates a command session and SETLOCAL obviously makes your variables local). If you ever want to preserve environment variables, this gets unpleasant.Tung
P
7

With regard to using :: instead of REM for comments: be careful! :: is a special case of a CALL label that acts like a comment. When used inside brackets, for instance in a FOR or IF loop, the function will prematurely exit. Very frustrating to debug!

See http://www.ss64.com/nt/rem.html for a full description.

(adding as a new answer instead of a comment to the first mention of this above because I'm not worthy of commeting yet :0)

Pimply answered 29/10, 2008 at 0:34 Comment(0)
D
7

Searching for an executable on the path (or other path-like string if necessary):

c:\> for %i in (cmd.exe) do @echo. %~$PATH:i
C:\WINDOWS\system32\cmd.exe

c:\> for %i in (python.exe) do @echo. %~$PATH:i
C:\Python25\python.exe

c:\>
Dandrea answered 29/10, 2008 at 0:34 Comment(1)
The where program can also do this. I'm not sure if this exists before Vista.Ockeghem
T
6

Local variables are still parsed for the line that ENDLOCAL uses. This allows for tricks like:

ENDLOCAL & SET MYGLOBAL=%SOMELOCAL% & SET MYOTHERGLOBAL=%SOMEOTHERLOCAL%

This is is a useful way to transmit results to the calling context. Specifically, %SOMELOCAL% goes out of scope as soon as ENDLOCAL completes, but by then %SOMELOCAL% is already expanded, so the MYGLOBAL is assigned in the calling context with the local variable.

For the same reason, if you decide to do:

ENDLOCAL & SET MYLOCAL=%MYLOCAL%

You'll discover your new MYLOCAL variable is actually now around as a regular environment variable instead of the localized variable you may have intended it to be.

Tung answered 29/10, 2008 at 0:34 Comment(0)
T
6

A lot of people use GOTO :EOF these days to terminate their batch files, but you can also use EXIT /B for this purpose.

The advantage behind using EXIT /B is that you can add an errorlevel after EXIT /B, and it will exit with that errorlevel.

Tung answered 29/10, 2008 at 0:34 Comment(0)
Z
5

Call Set - Expands Environment variables several levels deep.

Found this at http://ss64.com/nt/call.html#advanced from answer to another SO question Batch file variables initialized in a for loop

set VarName=Param
set Param=This

call set Answer=%%%Varname%%%
Echo %Answer%

gives

set VarName=Param
set Param=This
call set Answer=%Param%
Echo This
This
Zymometer answered 29/10, 2008 at 0:34 Comment(0)
S
5

Quick edit mode in cmd.exe is my favorite. This is slightly off topic, but when interacting with the command shell it can be a lifesaver. No, I'm not being hyperbolic--you will only see caret-capitol-v a certain number of times before you die; the more you see, the faster you die.

  1. Open up regedit (caution, not my fault, blue screen, etc)
  2. Go to HKCU/Console
  3. Set QuickEdit to 1

(You can set this from the UI as well, which is probably the better way. See the comments for instructions. Also there's a nice one line script to do this as well.)

Now, to copy, just left-click and drag to select and right click to copy. To paste, just right click.

NO MORE ^V^V^V^V^V^V^V^V^V^V^V^V^V^V!!!

Crap, I think I just killed somebody. Sorry!

Shiekh answered 29/10, 2008 at 0:34 Comment(5)
You can set this without editing the registry directly. Click on the command prompt icon in the upper-left corner of the window. Select Properties. On the Options tab check the QuickEdit Mode box.Goatsbeard
Yep, the Properties setting is the humane way to go. @Will, suggest you edit to make that the primary advice... But the regedit approach is still useful for say scripting this.Drolet
use 'alt+space e p' to paste clipboard at caret position dragging a folder from explorer to cmd window puts directory name at caret positionMaleficence
You can script it with reg add HKCU\Console /v QuickEdit /t REG_DWORD /d 1 /fOkie
I don't like quickedit coz it messes with my mouse behaviour. All I want is to be able to press Ctrl+V to paste! I feel an AHK script bubbling inside me... ;)Catricecatrina
D
5

Subroutines (outputs 42):

    @echo off
    call :answer 42
    goto :eof
:do_something
    echo %1
    goto :eof

and subroutines returning a value (outputs 0, 1, 2, and so on):

    @echo off
    setlocal enableextensions enabledelayedexpansion
    call :seq_init seq1
:loop1
    if not %seq1%== 10 (
        call :seq_next seq1
        echo !seq1!
        goto :loop1
    )
    endlocal
    goto :eof

:seq_init
    set /a "%1 = -1"
    goto :eof
:seq_next
    set /a "seq_next_tmp1 = %1"
    set /a "%1 = %seq_next_tmp1% + 1"
    set seq_next_tmp1=
    goto :eof
Dandrea answered 29/10, 2008 at 0:34 Comment(0)
G
4

You can use errorlevel to check if a given program is available on the system (current dir or path) where your batchfile will run. For this to work the program you are testing for must run, exit and set an exit code when it does. In the example I use -? as an arg to myExe, most CLI programs have a similar arg such as -h, --help, -v etc ... this ensures it simply runs and exits leaving or setting errorlevel 0

myExe -? >nul 2>&1 
Set errCode=%errorlevel%
@if %errCode% EQU 0 (
    echo myExe -? does not return an error (exists)
) ELSE (
    echo myExe -? returns an error (does not exist)
)

Yes, you could test errorlevel directly rather than assigning it to errCode but this way you can have commands between the test and the condition and you test the condition repeatedly as needed.

Gall answered 29/10, 2008 at 0:34 Comment(0)
R
4

Redirecting output to the console, even if the batch's output is already redirected to a file via the > con syntax.

Example: foo.cmd:

echo a
echo b > con

Calling:

foo.cmd > output.txt

This will result in "a" going to output.txt yet "b" going to the console.

Reorganize answered 29/10, 2008 at 0:34 Comment(0)
A
4
SHIFT

It's a way to iterate through a variable number of arguments passed into a script (or sub-routine) on the command line. In its simplest usage, it shifts %2 to be %1, %3 to be %2, and so-on. (You can also pass in a parameter to SHIFT to skip multiple arguments.) This makes the command "destructive" (i.e. %1 goes away forever), but it allows you to avoid hard-coding a maximum number of supported arguments.

Here's a short example to process command-line arguments one at a time:

:ParseArgs

if "%1"=="" (
    goto :DoneParsingArgs
)

rem ... do something with %1 ...

shift

goto :ParseArgs


:DoneParsingArgs

rem ...
Alie answered 29/10, 2008 at 0:34 Comment(2)
Sadly, SHIFT does not effect the value of %*, it only modifies the values of the individual params: %1, %2, etc.Drolet
Right. That's still possibly useful in some cases, but I agree that it's inconsistent...Alie
D
4

The subdirectory option on 'remove directory':

rd /s /q junk
Dandrea answered 29/10, 2008 at 0:34 Comment(0)
C
3

Get the current day, month and year (locale-independently):

for /f "tokens=1-4 delims=/-. " %%i in ('date /t') do (call :set_date %%i %%j %%k %%l)
goto :end_set_date

:set_date
if ("%1:~0,1%" gtr "9") shift
for /f "skip=1 tokens=2-4 delims=(-)" %%m in ('echo,^|date') do (set %%m=%1&set %%n=%2&set %%o=%3)
goto :eof

:end_set_date

echo day in 'DD' format is %dd%; month in 'MM' format is %mm%; year in 'YYYY' format is %yy%
Clime answered 29/10, 2008 at 0:34 Comment(1)
Wow, impressive and messy at the same time.Trinetta
C
3

A handy trick when you want to copy files between branches:

C:\src\branch1\mydir\mydir2\mydir3\mydir4>xcopy %cd:branch1=branch2%\foo*
Overwrite C:\src\branch1\mydir\mydir2\mydir3\mydir4\foo.txt (Yes/No/All)? y
C:\src\branch2\mydir\mydir2\mydir3\mydir4\foo.txt

This uses both the %cd% environment variable, and environment variable substitution.

Copyread answered 29/10, 2008 at 0:34 Comment(0)
R
3

The CHOICE command prompts the user for one of multiple options (via a single keypress)

@echo off
echo Please choose one of the following options
echo 1. Apple
echo 2. Orange
echo 3. Pizza
echo a, b, c. Something else
choice /c:123abc /m "Answer?"
set ChoiceLevel=%ErrorLevel%
echo Choice was: %ChoiceLevel%

%ChoiceLevel% will be the nth option selected (in the above example, b=5).

More details at the CHOICE reference page on SS64.com.

Reorganize answered 29/10, 2008 at 0:34 Comment(1)
Not sure if CHOICE is standard on Windows XP.Supertonic
C
3

For parsing stdin from inside a script you need that trick with the FOR and FIND commands:

for /f "tokens=*" %%g in ('find /V ""') do (
     :: do what you want with %%g
     echo %%g
)
Chimborazo answered 29/10, 2008 at 0:34 Comment(7)
SET /P is usually better for this.Tung
SET /P allows you to ask a question to the user and grab the input. The above is for parsing the std input when a program you do not control calls your batch file and pipe you some text. Suppose we use 'dir' as such a program for the sake of testing, 'dir | set /P data=My data' wont work. However the above trick would successfully parse the stdin passed on to the batch file.Chimborazo
Philibert, before saying something like "SET /P wont parse stdin" you really should test that first (or just look at Anton's entry here). It's what I do. :-/ Now, "dir | set /p data=My data" won't work because SET /P is set up in a separate context of cmd.exe which ends once the command finishes. The SET /P does in fact assign the data, but then it immediately disappears with the context once the command finishes running. Test out "DIR|(SET /P T=&SET T)" to see. Since the entirety of a batch script runs within the same context, it will work fine. If you tested a batch, you'd've noticed that.Tung
I did test your DIR|(SET /P T=&SET T). But it puts only the first DIR line into T. More to that, it becomes quite difficult to get and do something with T in your syntax. For instance DIR|(SET /P T=&echo %T%) wont work. If you care to provide a working example of successful parsing of stdin using SET /P I will be happy to learn from it.Chimborazo
:-/ Environment variables are parsed as soon as the line is read, in this case before the variable is even assigned, so of course an echo %T% won't work; you'd need to do DIR|(SET /P T=&CALL ECHO %T%) as per Adam. (Assuming T wasn't previously assigned a value, and that you are executing this from the command-line and not a batch.) Anyway, the practical applications lie in using the to parse stdin from inside a batch script, where you'd treat piped STDIN input the same as regular user input.Tung
Yet, my original comment remains. Can you provide a working example, inside a batch file, where you can actually do something useful with what's been put into T? Say, branch upon the result or print something or SET another variable for further use. More indeed, without calling a 2nd batch file to do the processing.Chimborazo
Well, I have on occasion made a batch script which requested user input and later piped input to automate it. On one occasion I even had a batch script call itself to pipe input into itself, but that's a little exotic.Tung
S
3

the correct format for loops with numeric variables is

for /l %%i in (startNumber, counter, endNumber) do echo %%i

more details > http://www.ss64.com/nt/for.html

Subserve answered 29/10, 2008 at 0:34 Comment(0)
G
2

Doskey Macros.

I've long lost the reference for this, but I still think it's a good idea, and worth sharing.

We can merge batch-files and doskey scripts into a single file. This might seem a little overly clever, but it works.

;= @echo off
;= rem Call DOSKEY and use this file as the macrofile
;= %SystemRoot%\system32\doskey /listsize=1000 /macrofile=%0%
;= rem In batch mode, jump to the end of the file
;= goto end

;= Doskey aliases
h=doskey /history

;= File listing enhancements
ls=dir /x $*

;= Directory navigation
up=cd ..
pd=pushd

;= :end
;= rem ******************************************************************
;= rem * EOF - Don't remove the following line.  It clears out the ';' 
;= rem * macro. Were using it because there is no support for comments
;= rem * in a DOSKEY macro file.
;= rem ******************************************************************
;=

It works by defining a fake doskey macro ';' which is gracefully (or silently) ignored when it is interpreted as a batch-file.

I've shortened the version listed here, if you want more, go here.

Generation answered 29/10, 2008 at 0:34 Comment(0)
G
2

Arrays in batch-files.

Set a value:

set count=1
set var%count%=42

Extract a value at the command-line:

call echo %var%count%%

Extract a value in a batch-file:

call echo %%var%count%%%

Note the extra strafing % signs.

The technique may look a little hairy, but it's quite useful. The above will print the contents of var1 (i.e. 42) as we explained. We could also replace the echo command with a set if we wanted to set some other variable to the value in var1. Meaning the following is a valid assignment at the command line:

call set x=%var%count%%

Then to see the value of va1:

echo %x%
Generation answered 29/10, 2008 at 0:34 Comment(0)
G
2

Find strings in files in a folder using the pipe '|' command:

dir /b *.* | findstr /f:/ "thepattern"
Godwit answered 29/10, 2008 at 0:34 Comment(0)
T
2

Using pushd to a UNC path will create a temporary drive mapping (starting with Z and working backward to find the next available letter) and put you in that drive and path. When you popd or exit the command prompt, the temporary mapping is gone.

   C:\>pushd \\yourmom\jukebox

   Z:\>pushd \\yourmom\business

   Y:\>

Also, not so much a batch tip as a command-line environment tip, but when you're working at the commandline with pushd and popd and network shares, it's useful to modify your prompt with the $+ (show pushd stack depth) and $M (show network share path).

   C:\utils>prompt $+$m$p$g

   C:\utils>pushd m:

   +\\yourmom\pub M:\>pushd c:\

   ++c:\>pushd
   M:\
   C:\utils  

   ++c:\>popd

   +\\yourmom\pub M:\>popd

   C:\utils>
Technocracy answered 29/10, 2008 at 0:34 Comment(0)
C
2

Findstr with regular expression support:

findstr "^[0-9].*" c:\windows\system32\drivers\etc\hosts
Caramel answered 29/10, 2008 at 0:34 Comment(0)
K
2

forfiles is very useful, for instance, to recursive delete all files older than two days

forfiles /D -2 /P "C:\Temp" /S /C "cmd /c del @path"
Krys answered 29/10, 2008 at 0:34 Comment(0)
D
2

For what it's worth, this is quite a good online reference for Windows CMD or batch files. I learned a few things I didn't know from it.

Dumbwaiter answered 29/10, 2008 at 0:34 Comment(0)
D
2

Inline comments using &::.

:: This is my batch file which does stuff.
copy thisstuff thatstuff  &:: We need to make a backup in case we screw up!

:: ... do lots of other stuff

How does this work? It's an ugly hack. The & is the command separator roughly approximating the ; of UNIX shells. The :: is another ugly hack that kinda-sorta emulates a REM statement. The end result is that you execute your command and then you execute a do-nothing command, thus approximating a comment.

This doesn't work in all situations, but it works often enough to be a useful hack.

Drain answered 29/10, 2008 at 0:34 Comment(0)
C
2

/c param for the cmd.exe itself, tells it to run and then do these commands.

I used to find myself frequently doing:

win+r, cmd RETURN, ping google.com RETURN

but now I just do:

win+r, cmd /c ping google.com RETURN

much faster. also helpful if you're using pstools and you want to use psexec to do some command line function on the remote machine.

EDIT: /k Works the same, but leaves the prompt open. This might come in handy more often.

Concent answered 29/10, 2008 at 0:34 Comment(2)
funny, I sware that didn't work on a pc once. working now though! thanks! The /c is still helpful for things that arent in the default path though...Concent
Replace the /c with /k and it'll stick around and show you the results.Conlen
J
2

I find the ease with which you can redirect the output of commands to files extremely useful:

DIR *.txt > tmp.txt
DIR *.exe >> tmp.txt

Single arrow creates, or overwrites the file, double arrow appends to it. Now I can open tmp.txt in my text editor and do all kinds of good stuff.

Jameson answered 29/10, 2008 at 0:34 Comment(1)
If you want just a plain list of files without all the directory info, use DIR /BExclude
P
1

Much like above, using CALL, EXIT /B, SETLOCAL & ENDLOCAL you can implement functions with local variables and return values.

example:

@echo off

set x=xxxxx
call :fun 10
echo "%x%"
echo "%y%"
exit /b

:fun
setlocal
set /a y=%1 + 1
endlocal & set x=%y%
exit /b

This will print:

"11"
""

The y variable never leaves the local scope, but because of the way CMD resolves a single line at a time, you can extract the value into the x variable in the parent scope.

Prowl answered 29/10, 2008 at 0:34 Comment(0)
E
1

Recursively search for a string in a directory tree:

findstr /S /C:"string literal" *.*

You can also use regular expressions:

findstr /S /R "^ERROR" *.log

Recursive file search:

dir /S myfile.txt
Etherealize answered 29/10, 2008 at 0:34 Comment(0)
C
1

Append files using copy:

copy file1.txt+file2.txt+file3.txt append.txt

Also, to set all CLI parameters to a single variable:

SET MSG=%*

This will take every word (or symbol) that is separated by spaces and save it to a single batch file variable. Technically, each parameter is %1, %2, $3, etc., but this SET command uses a wildcard to reference every parameter in stdin.

Batch File:

@SET MSG=%*
@echo %MSG%

Command Line:

C:\test>test.bat Hello World!
Hello World!
Churning answered 29/10, 2008 at 0:34 Comment(0)
C
1

Symbolic links:

mklink /d directorylink ..\realdirectory
mklink filelink realfile

The command is native on Windows Server 2008 and newer, including Vista and Windows 7. (It is also included in some Windows Resource Kits.)

Councillor answered 29/10, 2008 at 0:34 Comment(0)
H
1

Bail on error.

IF "%errorlevel%" NEQ "0" (
   echo "ERROR:  Something broke.  Bailing out."
   exit /B 1
)
Hogfish answered 29/10, 2008 at 0:34 Comment(0)
D
1

Remove surrounding quote.

for /f "useback tokens=*" %%a in ('%str%') do set str=%%~a

I recently have to write a batch file that is called by VS prebuild event and I want to pass in the project directory as parameter. In the batch file I need to concatenate the path with nested subfolder name, but first the surrounding quote need to be removed.

Diatomaceous answered 29/10, 2008 at 0:34 Comment(0)
A
1

Create and start editing a new file

copy con new.txt
This is the contents of my file
^Z

Ctrl+Z sends the ASCII EOF character. This is like heredocs in bash:

cat <<EOF > new.txt
This is the contents of my file
EOF
Archducal answered 29/10, 2008 at 0:34 Comment(0)
T
1

List all drives:

fsutil fsinfo drives
Tiein answered 29/10, 2008 at 0:34 Comment(0)
T
1

Hide input for an interactive batch script:

  @echo off

  echo hP1X500P[PZBBBfh#b##fXf-V@`$fPf]f3/f1/5++u5>in.com

  set /p secret_password="Enter password:"<nul

  for /f "tokens=*" %%i in ('in.com') do (set secret_password=%%i)

  del in.com
Tiein answered 29/10, 2008 at 0:34 Comment(2)
So we're creating in.com, an executable, and then running it from the for loop. For those of us not willing to try it out and that don't speak Assembly, what exactly does that .com file do?Lawgiver
It will end up calling DOS (int 0x21) function 0x0A which read from the standard input. Disassembly link NB. The .com file will not work in 64-bit versions of Windows.Arica
D
1

The goto :eof pasteboard

I add "goto :eof" to end of my scripts as a handy space for code fragments. That way I can quickly copy/paste to and from this area, without having to comment/uncomment.

goto :eof
:: code scraps
call this.bat
call that.bat
set TS=%DATE:~10%%DATE:~4,2%%DATE:~7,2%-%TIME:~0,2%%TIME:~3,2%%TIME:~6%%
for /R C:\temp\ %%G in (*.bak) DO del %%G
Drolet answered 29/10, 2008 at 0:34 Comment(0)
T
1

A method to set the errorlevel to any number you desire:

CMD /C EXIT number
Tung answered 29/10, 2008 at 0:34 Comment(0)
E
1

Setting environment variables from a file with SET /P

SET /P SVNVERSION=<ver.tmp
Elaina answered 29/10, 2008 at 0:34 Comment(1)
The problem with that is that only the first line of text turns into the value. It might be usable, but it doesn't seem useful.Tung
T
1

I would say DEBUG.EXE is a VERY useful and VERY underused feature of batch files.

The DEBUG command allows you to...

  1. Assemble and disassemble 16-bit code
  2. Read/write memory (Modern protected memory makes this considerably less useful.)
  3. Read data sectors from the hard drive, raw
  4. Hex edit

In short, this tool is EXTREMELY powerful. It might not be used much these days anymore, but the power to call up and control this functionality from a batch script adds a staggering amount of power to batch scripting.

NOTE: Microsoft has removed this command from 64 bit editions of Windows Xp and Vista and intends to remove it from Windows 7 altogether, from what I've heard.

Tung answered 29/10, 2008 at 0:34 Comment(1)
They removed the 16-bit debug.exe since the NTVDM emulator is not included in the 64-bit versions of Windows.Arica
D
1

Allows you to change directory based on environment variable without having to specify the '%' directive. If the variable specified does not exist then try the directory name.

@if defined %1 (call cd "%%%1%%") else (call cd %1)
Dickens answered 29/10, 2008 at 0:34 Comment(0)
K
1

Multiple commands in one line, useful in many situations:

& Used to combine two commands, executes command1 and then command2
&& A conditional combination, executes command2 if command1 completes successfully
¦¦ Command2 executes only if command1 does not complete successfully.

Examples:

:: ** Edit the most recent .TXT file and exit, useful in a .CMD / .BAT **
FOR /F %%I IN ('DIR *.TXT /B /O:-N') DO NOTEPAD %%I & EXIT


:: ** If exist any .TXT file, display the list in NOTEPAD, if not it 
:: ** exits without any error (note the && and the 2> error redirection)
DIR *.TXT > TXT.LST 2> NUL && NOTEPAD TXT.LST
Kush answered 29/10, 2008 at 0:34 Comment(1)
Actually, :: Is a special case of a label, and not a comment. See ss64.com/nt/rem.html If your batch file is complex enough for this to cause subtle problems ... it's probably time to switch to another language.Clamp
F
1

Here how to build a CLASSPATH by scanning a given directory.

setlocal ENABLEDELAYEDEXPANSION
if defined CLASSPATH (set CLASSPATH=%CLASSPATH%;.) else (set CLASSPATH=.)
FOR /R .\lib %%G IN (*.jar) DO set CLASSPATH=!CLASSPATH!;%%G
Echo The Classpath definition is %CLASSPATH%

works in XP (or better). With W2K, you need to use a couple of BAT files to achieve the same result.

It's not needed for 1.6 since you can specify a wildcard directly in CLASSPATH (ex. -cp ".\lib*").

Frias answered 29/10, 2008 at 0:34 Comment(0)
G
0

You can modify a batch file while it is running. For example you can add a forgotten pause to the end of the file while it's running if you wanted to see the results before the batch file quit.

see Changing a batch file when its running

I personally think of this more as a gotcha than a feature.

Geostrophic answered 29/10, 2008 at 0:34 Comment(1)
That can work as long as you edit below the currently executing command. Changing anything above that gives unpredictable results, as the content of the file suddenly shifts up or down from the perspective of the cmd parser. - @cavalier-edit-meisterDrolet
H
0

To get the current date / time to use for log files, etc., I use this in my batch files:

for /f "usebackq tokens=1,2,3,4,5,6,7 delims=/:. " %%a in (`echo %DATE% %TIME%`) do set NOW=%%d%%b%%c_%%e%%f%%g
set LOG=output_%NOW%.log
Helium answered 29/10, 2008 at 0:34 Comment(0)
N
0

I use them as quick shortcuts to commonly used directories. An example file named "sandbox.bat" which lives in a directory in my PATH

EXPLORER "C:\Documents and Settings\myusername\Desktop\sandbox"

Invoking the script is just WIN+R --> sandbox

Nothingness answered 29/10, 2008 at 0:34 Comment(1)
You can do the same thing with shortcuts. And I highly recommend Launchy if you like to launch things this way. It can become <Win>+<Space> (or whatever shortcut you want) --> <S>, <Enter>.Geist
F
0

Line-based execution

While not a clear benefit in most cases, it can help when trying to update things while they are running. For example:

UpdateSource.bat

copy UpdateSource.bat Current.bat
echo "Hi!"

Current.bat

copy UpdateSource.bat Current.bat

Now, executing Current.bat produces this output.

HI!

Watch out though, the batch execution proceeds by line number. An update like this could end up skipping or moving back a line if the essential lines don't have exactly the same line numbers.

Freehand answered 29/10, 2008 at 0:34 Comment(0)
W
0

FIND as a replacement for grep.
I hacked a little "phonebook" for myself with find. Very usefull:

@echo off
:begin
set /p term=Enter query: 
type phonebookfile.txt |find /i "%term%"
if %errorlevel% == 0 GOTO :choose
echo No entry found
set /p new_entry=Add new entry: 
echo %new_entry% >> phonebookfile.txt 
:choose
set /p action=(q)uit, (n)ew query or (e)dit? [q] 
if "%action%"=="n" GOTO anfang
if "%action%"=="e" (
    notepad phonebookfile.txt
    goto :choose
)

Very fast and effective.

Window answered 29/10, 2008 at 0:34 Comment(0)
L
0

When passing an unknown number of parameters to a batch file, e.g. when several files are dragged and dropped onto the batch file to launch it, you could refer to each parameter variable by name, e.g.

TYPE %1
TYPE %2
TYPE %3
TYPE %4
TYPE %5
...etc

but this gets very messy when you want to check if each parameter exists:

if [%1] NEQ [] (
TYPE %1
)
if [%2] NEQ [] (
TYPE %2
)
if [%3] NEQ [] (
TYPE %3
)
if [%4] NEQ [] (
TYPE %4
)
if [%5] NEQ [] (
TYPE %5
)
...etc

Also, you can only accept a limited number of parameters with this approach.

Instead, try using the SHIFT command:

:loop
IF [%1] NEQ [] (
TYPE %1
) ELSE (
GOTO end
)
SHIFT
GOTO loop
:end

SHIFT will move all the parameters down by one, so %2 becomes %1 and %3 becomes %2 etc.

Lassiter answered 29/10, 2008 at 0:34 Comment(0)
T
0

There is also the EDLIN command. While it may be an old bastard tool once used for line-based text editing, the fact that it's controllable from the command line makes it rather useful for batch scripting, mostly because, just like any other case you'd be using EDLIN, it's the only tool available. After all, EDLIN is not a tool you would ordinarily want to use for text editing, unless you are somewhat masochistic. To quote Tim Patterson (the fellow who wrote it): "I was aghast when I heard that IBM was using it and not throwing it out the window."

NOTE: EDLIN adds old-fashioned EOF (1A) markers to files it edits. If you need to remove them, you'll probably have to use DEBUG.

Tung answered 29/10, 2008 at 0:34 Comment(0)
I
0

I really like this Windows XP Commands reference, as well as the Syntax link at the top; it covers many of the tips and tricks already found in other answers.

Instrumentalist answered 29/10, 2008 at 0:34 Comment(0)
C
0

The IF command! Without it my batch file was junk!

@echo off
IF exist %windir%\system32\iexplore.exe goto end

echo Hmm... it seems you do not have Internet Explorer.
echo Great! You seem to understand ;)

:end
echo Hmm... You have Internet Explorer.
echo That is bad :)
Countable answered 29/10, 2008 at 0:34 Comment(1)
You need to add goto :eof between those echo sections.Drolet
C
0

This batch file works both with simple files as well as directories as command line parameters (you can mix them in any order). The loop runs the command ('echo' in this example) on any specified file, if a parameter is a directory it runs the command recursively on each file in it.

@echo off
for /f "delims=" %%f in ('dir %* /a-d /b /s') do echo %%f
Coryphaeus answered 29/10, 2008 at 0:34 Comment(0)
E
0

A very old (ca 1990) trick to get the total size of the environment variables:

set > test
dir test
del test
Exercitation answered 29/10, 2008 at 0:34 Comment(0)
C
0

When using command extensions shell options in a script, it is HIGHLY suggested that you do the following trick at the beginning of your scripts.

-- Information pasted from http://www.ss64.com/nt/setlocal.html

SETLOCAL will set an ERRORLEVEL if given an argument. It will be zero if one of the two valid arguments is given and one otherwise.

You can use this in a batch file to determine if command extensions are available, using the following technique:

VERIFY errors 2>nul
SETLOCAL ENABLEEXTENSIONS
IF ERRORLEVEL 1 echo Unable to enable extensions

This works because "VERIFY errors" sets ERRORLEVEL to 1 and then the SETLOCAL will fail to reset the ERRORLEVEL value if extensions are not available (e.g. if the script is running under command.com)

If Command Extensions are permanently disabled then SETLOCAL ENABLEEXTENSIONS will not restore them.

Chimborazo answered 29/10, 2008 at 0:34 Comment(2)
That's for when you want to actually make code that runs on older windows computers. Most of the time it's only for your own code and even if you do share it nowadays it's a safe assumption their windows is recent enough for SETLOCAL ENABLEEXTENSIONS to work, so this isn't really needed anymore.Tung
ENABLEEXTENSIONS can be forced disabled. Thus calling SETLOCAL ENABLEEXTENSIONS should be one of the first lines to run anyways. The other two lines add a marginal safety at a very low expense. If you are writing a batch as part of an installer or something that needs bulletproofing this trick easily covers your bottom against it. I am sorry to say that I still have to support product installation on Win95/Win98 systems!Chimborazo
M
0
HELP

When working with different OS version it's important to know what commands are available natively. Typing HELP at the command prompt shows what commands are available, with a brief description of what they do.

cmd.exe /? 

This will list all the command line parameters for launching a command prompt as well as registry tweaks that change system wide behavior.

Mate answered 29/10, 2008 at 0:34 Comment(0)
G
0

here's one trick that I use to run My Nant Build script consecutively without having to click the batch file over and over again.

:CODELINE
NANT.EXE -buildfile:alltargets.build -l:build.log build.product
@pause
GOTO :CODELINE

What will happen is that after your solution finished building, it will be paused. And then if you press any key it will rerun the build script again. Very handy I must say.

Gnosticism answered 29/10, 2008 at 0:34 Comment(3)
That's not much of a trick, just a recursive goto loop. You might as well skip writing :CODELINE and GOTO:CODELINE and instead just replace GOTO :CODELINE with @"%~0" (@"%~0" starts the batch from the beginning again)Tung
I think the GOTO is clearer than @"%~0" - if I saw @"%~0" in a batch file I would probably scream WTF? And to be honest @"%~0" is not particularly Googlable either in order to look it up :)Catricecatrina
Actually I'd just write @%0 now, as I've learned that %0 is an irregular beast and gives the full expanded file name including spaces wrapped within quotation marks while others don't work that way with spaces (see FOR /? for more info). And Demon, that's your problem - :P. You could also just add a comment like "@REM The %0 represents the batch file's name, causing the batch file to repeat itself."Tung
D
0

For loops with numeric counters (outputs 1 through 10):

for /l %i in (1,1,10) do echo %i
Dandrea answered 29/10, 2008 at 0:34 Comment(0)
E
-1

One of the most common requirements of batch scripting is to log the output generated for later review. Yes, you can redirect the stdout and stderr to a file but then you can't see what is going on unless you tail the log file.

So consider running your batch scripts using a stdout/stderr logging utility like logger which will log the output with a timestamp and you are still able to see the script progress as it happens.

Yet another stdout/stderr logging utility

Yet another stdout/stderr logging utility [2010-08-05]
Copyright (C) 2010 LoRd_MuldeR <[email protected]>
Released under the terms of the GNU General Public License (see License.txt)

Usage:
  logger.exe [logger options] : program.exe [program arguments]
  program.exe [program arguments] | logger.exe [logger options] : -

Options:
  -log <file name>  Name of the log file to create (default: "<program> <time>.log")
  -append           Append to the log file instead of replacing the existing file
  -mode <mode>      Write 'stdout' or 'stderr' or 'both' to log file (default: 'both')
  -format <format>  Format of log file, 'raw' or 'time' or 'full' (default: 'time')
  -filter <filter>  Don't write lines to log file that contain this string
  -invert           Invert filter, i.e. write only lines to log file that match filter
  -ignorecase       Apply filter in a case-insensitive way (default: case-sensitive)
  -nojobctrl        Don't add child process to job object (applies to Win2k and later)
  -noescape         Don't escape double quotes when forwarding command-line arguments
  -silent           Don't print additional information to the console
  -priority <flag>  Change process priority (idle/belownormal/normal/abovenormal/high)
  -inputcp <cpid>   Use the specified codepage for input processing (default: 'utf8')
  -outputcp <cpid>  Use the specified codepage for log file output (default: 'utf8')
Erickaericksen answered 29/10, 2008 at 0:34 Comment(0)
H
-1

To set an enivroment variable from the first line of a file, I use this:

rem a.txt contains one line: abc123
set /p DATA=<a.txt
echo data: %DATA%

This will output: abc123

Helium answered 29/10, 2008 at 0:34 Comment(0)
C
-2

Extract random lines of text

@echo off

:: Get time (alas, it's only HH:MM xM

for /f %%a in ('time /t') do set zD1=%%a



:: Get last digit of MM

set zD2=%zD1:~4,1%



:: Seed the randomizer, if needed

if not defined zNUM1 set /a zNUM1=%zD2%


:: Get a kinda random number

set /a zNUM1=zNUM1 * 214013 + 2531011

set /a zNUM2=zNUM1 ^>^> 16 ^& 0x7fff


:: Pull off the first digit

:: (Last digit would be better, but it's late, and I'm tired)

set zIDX=%zNUM2:~0,1%


:: Map it down to 0-3

set /a zIDX=zIDX/3


:: Finally, we can set do some proper initialization

set /a zIIDX=0

set zLO=

set zLL=""


:: Step through each line in the file, looking for line zIDX

for /f "delims=@" %%a in (c:\lines.txt) do call :zoo  %zIDX%  %%a


:: If line zIDX wasn't found, we'll settle for zee LastLine

if "%zLO%"=="" set zLO=%zLL%

goto awdun


:: See if the current line is line zIDX

:zoo


:: Save string of all parms

set zALL=%*


:: Strip off the first parm (sure hope lines aren't longer than 254 chars)

set zWORDS=%zALL:~2,255%


:: Make this line zee LastLine

set zLL=%zWORDS%


:: If this is the line we're looking for, make it zee LineOut

if {%1}=={%zIIDX%} set zLO=%zWORDS%


:: Keep track of line numbers

set /a zIIDX=%zIIDX% + 1

goto :eof




:awdun

echo ==%zLO%==


:: Be socially responsible

set zALL=

set zD1=

set zD2=

set zIDX=

set zIIDX=

set zLL=

set zLO=

:: But don't mess with seed

::set zNUM1=

set zNUM2=

set zWORDS=
Chamblee answered 29/10, 2008 at 0:34 Comment(1)
Downrated, this isn't a hidden feature; it's a meaningless batch. You also use way too much whitespace, used a homegrown method of extracting time instead of just using %TIME%, made your own random seed for no apparent reason instead of using %RANDOM%, and removed variables by hand instead of just using SETLOCAL and ENDLOCAL.Tung

© 2022 - 2024 — McMap. All rights reserved.