232
votes

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?)

0

91 Answers 91

185
votes

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
4
  • 21
    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.
    – Cheeso
    Commented Jul 4, 2009 at 23:48
  • Could you please explain this little scriptlet?
    – guerda
    Commented Oct 23, 2009 at 12:40
  • 2
    @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 /?. Commented Aug 7, 2010 at 18:06
  • The in depth discussion about this topic, at long commands split over multiple lines
    – jeb
    Commented Mar 17, 2011 at 12:14
150
votes
PUSHD path

Takes you to the directory specified by path.

POPD

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

7
  • 5
    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.
    – Kibbee
    Commented Oct 29, 2008 at 0:54
  • 4
    Run 'cmd.exe' then type 'help', then type 'help pushd' or 'pushd /?'.
    – paxdiablo
    Commented Oct 29, 2008 at 1:25
  • 86
    If you pushd to a UNC path, it will automatically map a drive for you and the popd will unmap it.
    – Ferruccio
    Commented Oct 29, 2008 at 4:11
  • in csh, if I recall, a pushd with no arg just cycled the stack. But that doesn't work on cmd.exe, does it?
    – Cheeso
    Commented Jul 4, 2009 at 23:49
  • 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.)
    – idbrii
    Commented Mar 24, 2011 at 16:41
109
votes

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.

14
  • 1
    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 ." ;)
    – Paulius
    Commented Dec 2, 2008 at 18:38
  • 5
    'explorer' also does the same thing as 'start' C:\some_directory>explorer .
    – Ray
    Commented Feb 4, 2009 at 23:41
  • 1
    I tend to type this as [ start "" . ] (brackets for clarity) because start is sometimes finicky about the first param being a title. Commented Sep 15, 2009 at 19:49
  • 1
    If you happen to be on a Mac, open . does the same thing.
    – Grant Paul
    Commented Nov 6, 2010 at 0:24
  • 1
    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...
    – idbrii
    Commented Mar 24, 2011 at 16:45
87
votes

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
4
  • 8
    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. Commented Nov 20, 2008 at 10:22
  • 47
    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.
    – mihi
    Commented Apr 25, 2009 at 18:05
  • 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.
    – Joey
    Commented Mar 18, 2011 at 17:40
  • You can even use goto : to jump to the label. :-) and goto -) will also work. Commented Jun 9, 2011 at 16:16
79
votes

Variable substrings:

> set str=0123456789
> echo %str:~0,5%
01234
> echo %str:~-5,5%
56789
> echo %str:~3,-3%
3456
4
  • 1
    @furtelwart sounds like that could be the batch motto Commented Jul 21, 2010 at 5:19
  • this great for formatting dates (however the problem I found was that vista/7 and xp output DATE differently)
    – Daniel
    Commented Sep 1, 2010 at 22:34
  • 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.
    – RolKau
    Commented Mar 24, 2011 at 10:44
  • 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. Commented Feb 1, 2012 at 8:37
72
votes

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...

5
  • 4
    I've found the batch files' FOR loops limited and terrible to write, but they are useful sometimes.
    – ya23
    Commented Dec 17, 2008 at 12:21
  • 2
    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. Commented Jul 3, 2009 at 0:39
  • 11
    Underused or not, it is torture. (Some would argue a necessary evil.)
    – harpo
    Commented Sep 10, 2009 at 20:37
  • 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.
    – VitalyB
    Commented Mar 24, 2011 at 16:43
  • 1
    @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 : )
    – idbrii
    Commented Mar 24, 2011 at 16:47
60
votes

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.

2
  • 3
    Would be even cooler if you checked the %1 for "/?" and then you could echo that section as help text. Commented Sep 10, 2009 at 20:31
  • 6
    Hmm, literate batch programming ?! Commented Oct 1, 2010 at 10:37
54
votes

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

set BAT_HOME=%~dp0
echo %BAT_HOME%
cd %BAT_HOME%
6
  • I usually use %CD% for this. Maybe it is not available in all DOS shell versions? Commented Nov 14, 2008 at 6:17
  • 11
    %CD% is the current directory while %~dp0 is the directory where the running script is located.
    – RealHowTo
    Commented Nov 17, 2008 at 2:22
  • Also, I don't think %CD% existed before...XP, maybe. I know some older versions of Windows don't have it. Commented Sep 29, 2009 at 18:23
  • 1
    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.
    – ketorin
    Commented Apr 13, 2010 at 11:47
  • cd or pushd %BATH_HOME% will not work if you run a batch on a network path.
    – Benoit
    Commented Sep 25, 2010 at 6:39
49
votes

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
0
43
votes

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.

6
  • 6
    You should rather use goto :eof instead of exit /b, does the same thing but is the more standard way to do it. Commented Nov 7, 2008 at 1:27
  • 2
    There's a standard for this? O_o
    – Paulius
    Commented Dec 2, 2008 at 18:40
  • 3
    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.
    – Ferruccio
    Commented Feb 23, 2009 at 17:46
  • 3
    However, if you want a subroutine to set an errorlevel, you will need to use exit /b. For example: exit /b 3
    – Chris Noe
    Commented Jul 6, 2009 at 20:28
  • 6
    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). Commented Aug 4, 2009 at 12:29
42
votes

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
3
  • 2
    Even better is to put this in a file like sleep.bat to save you the trouble of rewriting it over and over.
    – erjiang
    Commented Oct 11, 2009 at 1:01
  • 1
    ...and put the sleep.bat in some directory in the PATH environment variable Commented Oct 23, 2009 at 12:38
  • I'm against putting this outside, makes the less portable... across Windows systems.
    – sorin
    Commented Sep 28, 2010 at 9:31
37
votes

Escaping the "plumbing":

echo ^| ^< ^> ^& ^\ ^^
4
  • 3
    I'll bet the DOS escape character is not well known. Good one.
    – Joshua
    Commented May 24, 2009 at 18:07
  • 12
    Ah, that'd explain why it's the line continuation operator as well -- it escapes the newline, just like \ in bash...
    – leander
    Commented May 24, 2009 at 18:22
  • @leander: Yes, but it only can escape the LF (and not the CR), because all CRs are removed before
    – jeb
    Commented Nov 6, 2010 at 0:28
  • So this is why using git on Windows to diff against the previous commit (HEAD^) is problematic. Commented Mar 24, 2011 at 16:39
31
votes

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
3
  • 2
    Doesn't work with filenames which has spaces in their names... This works: for /f "tokens=*" %i in ('dir /on /b *.jpg') do echo --^> %i
    – doekman
    Commented Dec 2, 2008 at 10:31
  • 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.
    – paxdiablo
    Commented Dec 2, 2008 at 10:57
  • That's the craziest syntax I've seen yet. Does it work if you made this backtick.bat and pass in the string?
    – idbrii
    Commented Mar 24, 2011 at 16:55
30
votes

Creating an empty file:

> copy nul filename.ext
4
  • 6
    @devio: echo. puts an empty line. so the file wouldn't be empty!
    – Paulius
    Commented Dec 2, 2008 at 18:40
  • 4
    I use type nul > filename.ext for that.
    – Benoit
    Commented Mar 24, 2011 at 16:52
  • Nice I was wondering if there was a touch equivalent for a long time.
    – jdelator
    Commented Mar 24, 2011 at 21:38
  • I’ve always used ren > blah.txt
    – Synetech
    Commented Mar 26, 2011 at 13:04
28
votes

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.

6
  • 1
    Do you know how this works? What's the meaning of the 2>&1 bit? Commented Nov 20, 2008 at 10:37
  • 12
    The >nul redirects STDOUT to nul. The 2>&1 redirects STDERR to wherever STDOUT is pointing.
    – aphoria
    Commented Dec 2, 2008 at 18:30
  • 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.)
    – leander
    Commented May 24, 2009 at 17:59
  • 1
    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. Commented Jul 6, 2009 at 17:46
  • 1
    If you don't have pskill or tskill, most Windows systems I've used come with taskkill.
    – idbrii
    Commented Mar 24, 2011 at 16:56
25
votes
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.

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...
    – Blank
    Commented Oct 29, 2008 at 3:26
  • 15
    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...
    – leander
    Commented May 24, 2009 at 17:57
  • 4
    +1 to Charlie Somerville, this is so known every game programmer's 'go.bat' used it back in the early 90s.
    – LiraNuna
    Commented Sep 9, 2009 at 6:18
  • 6
    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. Commented Sep 15, 2009 at 20:00
  • 1
    @gnud: you can still pipe to the script: echo.|batch-with-pause.bat will have the same effect as pressing the 'any-key'... Commented Aug 7, 2010 at 18:39
25
votes

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.

18
votes

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%
17
votes

Integer arithmetic:

> SET /A result=10/3 + 1
4
4
  • How long have SET got the ability to calculate? Windows XP?
    – chakrit
    Commented Apr 28, 2009 at 16:06
  • 1
    If you are asking how big the values can be, I believe this is 32-bit. So +/- 2 billion.
    – Chris Noe
    Commented Apr 29, 2009 at 18:15
  • 1
    I think the question was, how long has SET been able to calculate? Since Windows XP?
    – Michael Myers
    Commented May 21, 2009 at 18:56
  • 3
    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...
    – RBerteig
    Commented Aug 4, 2009 at 17:41
16
votes

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.

15
votes

Output a blank line:

echo.
15
votes

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

if foo if bar baz
1
  • 1
    This is really just a shortcut for nesting ifs: if foo ( if bar ( baz ) ) (Imagine newlines after the brackets.)
    – idbrii
    Commented Mar 24, 2011 at 17:04
14
votes

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.

2
  • 1
    That's an ANSI DOS file - ASCII is 7bit/char.
    – MarkJ
    Commented Apr 1, 2010 at 14:26
  • 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.
    – sorin
    Commented Sep 28, 2010 at 9:41
14
votes

if block structure:

if "%VS90COMNTOOLS%"=="" (
  echo: Visual Studio 2008 is not installed
  exit /b
)
3
  • 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. Commented Mar 10, 2009 at 16:08
  • You also can't use labels there (which includes those :: style comments) because it will prematurely end the if statement. Commented Sep 5, 2009 at 21:44
  • 2
    @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.
    – Joey
    Commented Mar 11, 2010 at 16:39
12
votes

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
0
12
votes

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
2
  • 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?
    – Chris Noe
    Commented Nov 4, 2008 at 20:48
  • 2
    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...
    – ℳ  .
    Commented Apr 13, 2010 at 5:57
11
votes

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.

0
11
votes

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 ?

2
  • edited; the _'s were interpreted as italics. Nice bit of code.
    – user1228
    Commented Oct 31, 2008 at 13:15
  • @Duncan Smart: not true, also works in UK English (although technically it should be "colour", grrr) Commented Sep 10, 2009 at 20:40
10
votes

Total control over output with spacing and escape characters.:

echo.    ^<resourceDir^>/%basedir%/resources^</resourceDir^>
3
  • 1
    How does that work? The dot demarcates the beginning of the text output?
    – Chris Noe
    Commented Oct 29, 2008 at 0:54
  • 3
    "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.
    – paxdiablo
    Commented Oct 29, 2008 at 0:57
  • 1
    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(
    – jeb
    Commented Nov 6, 2010 at 0:35
9
votes

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
3
  • 2
    Surely DATE /T returns 29/10/2008 in Europe and 10/29/2008 in the US... so some localisation may be required! ;-)
    – Eggs McLaren
    Commented Oct 29, 2008 at 15:23
  • That's right! But you can abuse the date command to find out which date format is used.
    – remonedo
    Commented Oct 30, 2008 at 15:34
  • 4
    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. Commented Jul 6, 2009 at 17:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.