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

Community
  • 1
  • 1
Chris Noe
  • 36,411
  • 22
  • 71
  • 92

91 Answers91

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
Kurt Pfeifle
  • 86,724
  • 23
  • 248
  • 345
Chris Noe
  • 36,411
  • 22
  • 71
  • 92
  • 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 Jul 04 '09 at 23:48
  • Could you please explain this little scriptlet? – guerda Oct 23 '09 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 /?`. – Kurt Pfeifle Aug 07 '10 at 18:06
  • The in depth discussion about this topic, at [long commands split over multiple lines](http://stackoverflow.com/questions/69068/long-commands-split-over-multiple-lines-in-vista-dos-batch-bat-file/4455750#4455750) – jeb Mar 17 '11 at 12:14
150
PUSHD path

Takes you to the directory specified by path.

POPD

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

raven
  • 18,004
  • 16
  • 81
  • 112
  • 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 Oct 29 '08 at 00:54
  • 4
    Run 'cmd.exe' then type 'help', then type 'help pushd' or 'pushd /?'. – paxdiablo Oct 29 '08 at 01:25
  • 86
    If you pushd to a UNC path, it will automatically map a drive for you and the popd will unmap it. – Ferruccio Oct 29 '08 at 04: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 Jul 04 '09 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 Mar 24 '11 at 16:41
  • @raven why did you roll back previous edit, isn't the UNC path working? – CharlesB Apr 08 '11 at 21:21
  • @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. – raven Apr 08 '11 at 23:27
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.

LeopardSkinPillBoxHat
  • 28,915
  • 15
  • 75
  • 111
  • 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 Dec 02 '08 at 18:38
  • 5
    'explorer' also does the same thing as 'start' C:\some_directory>explorer . – Ray Feb 04 '09 at 23:41
  • +1 Use it all the time :-) ... CD with tab completion in command prompt then pops up an explorer window with start . :-) – chakrit Apr 28 '09 at 15:49
  • I prefer "C:\some_directory> explorer /e,." this will open explorer in Folder View – Justin Jul 06 '09 at 18:01
  • 1
    I tend to type this as [ start "" . ] (brackets for clarity) because start is sometimes finicky about the first param being a title. – system PAUSE Sep 15 '09 at 19:49
  • Is the reverse available -- navigate through explorer to a desired folder, then click something to open a command Window "in" that folder? – Philip Kelley Nov 02 '09 at 16:53
  • @Philip - There are various powertool utilities which allow this. Here's an example, but I haven't tried this particular software myself: http://www.petri.co.il/add_command_prompt_here_shortcut_to_windows_explorer.htm – LeopardSkinPillBoxHat Nov 03 '09 at 10:11
  • I just type `start.` (No space.) – Coding With Style Oct 19 '10 at 19:21
  • 1
    If you happen to be on a Mac, `open .` does the same thing. – Grant Paul Nov 06 '10 at 00:24
  • @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". – idbrii Mar 24 '11 at 16:44
  • 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 Mar 24 '11 at 16:45
  • 1
    `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) – bart Mar 24 '11 at 22:10
  • @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. – Halil Özgür Feb 01 '12 at 08:30
  • 1
    @HalilÖzgür- Did you include the period ("`.`") after the `explorer` command? It needs that to open the current directory. `C:\some_directory>explorer .` – Ray Feb 01 '12 at 17:52
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
Chris Noe
  • 36,411
  • 22
  • 71
  • 92
  • 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. – Scott Langham Nov 20 '08 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 Apr 25 '09 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 Mar 18 '11 at 17:40
  • You can even use `goto :` to jump to the label. `:-)` and `goto -)` will also work. – Sven Marnach Jun 09 '11 at 16:16
79

Variable substrings:

> set str=0123456789
> echo %str:~0,5%
01234
> echo %str:~-5,5%
56789
> echo %str:~3,-3%
3456
Chris Noe
  • 36,411
  • 22
  • 71
  • 92
  • 1
    @furtelwart sounds like that could be the batch motto – rzrgenesys187 Jul 21 '10 at 05:19
  • this great for formatting dates (however the problem I found was that vista/7 and xp output DATE differently) – Daniel Sep 01 '10 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 Mar 24 '11 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. – Halil Özgür Feb 01 '12 at 08:37
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...

TheSoftwareJedi
  • 34,421
  • 21
  • 109
  • 151
  • 4
    I've found the batch files' FOR loops limited and terrible to write, but they are useful sometimes. – ya23 Dec 17 '08 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. – Coding With Style Jul 03 '09 at 00:39
  • 11
    Underused or not, it is torture. (Some would argue a necessary evil.) – harpo Sep 10 '09 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 Mar 24 '11 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 Mar 24 '11 at 16:47
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.

Patrick Cuff
  • 28,540
  • 12
  • 67
  • 94
54

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

set BAT_HOME=%~dp0
echo %BAT_HOME%
cd %BAT_HOME%
RealHowTo
  • 34,977
  • 11
  • 70
  • 85
  • I usually use %CD% for this. Maybe it is not available in all DOS shell versions? – Saul Dolgin Nov 14 '08 at 06:17
  • 11
    %CD% is the current directory while %~dp0 is the directory where the running script is located. – RealHowTo Nov 17 '08 at 02:22
  • Also, I don't think %CD% existed before...XP, maybe. I know some older versions of Windows don't have it. – Thomas Owens Sep 29 '09 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 Apr 13 '10 at 11:47
  • cd or pushd %BATH_HOME% will not work if you run a batch on a network path. – Benoit Sep 25 '10 at 06:39
  • 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%"` – MikeOnline Mar 02 '12 at 03:20
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
jeb
  • 78,592
  • 17
  • 171
  • 225
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.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • 6
    You should rather use goto :eof instead of exit /b, does the same thing but is the more standard way to do it. – Philibert Perusse Nov 07 '08 at 01:27
  • 2
    There's a standard for this? O_o – Paulius Dec 02 '08 at 18:40
  • It's not "more standard", it's more common because most people don't know about the /b option of exit. – Ferruccio Dec 31 '08 at 23:28
  • 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 Feb 23 '09 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 Jul 06 '09 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). – Scott Langham Aug 04 '09 at 12:29
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
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
37

Escaping the "plumbing":

echo ^| ^< ^> ^& ^\ ^^
Chris Noe
  • 36,411
  • 22
  • 71
  • 92
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
Kurt Pfeifle
  • 86,724
  • 23
  • 248
  • 345
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 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 Dec 02 '08 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 Dec 02 '08 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 Mar 24 '11 at 16:55
30

Creating an empty file:

> copy nul filename.ext
Helen
  • 87,344
  • 17
  • 243
  • 314
rbrayb
  • 46,440
  • 34
  • 114
  • 174
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.

aphoria
  • 19,796
  • 7
  • 64
  • 73
  • 1
    Do you know how this works? What's the meaning of the 2>&1 bit? – Scott Langham Nov 20 '08 at 10:37
  • 12
    The >nul redirects STDOUT to nul. The 2>&1 redirects STDERR to wherever STDOUT is pointing. – aphoria Dec 02 '08 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 May 24 '09 at 17:59
  • 1
    For those of you wondering where PSKILL comes from, check out http://www.sysinternals.com/. If you're on a Pro edition, you should have a native TSKILL command that's more or less the same. – Coding With Style Jul 06 '09 at 17:46
  • 1
    If you don't have pskill or tskill, most Windows systems I've used come with `taskkill`. – idbrii Mar 24 '11 at 16:56
  • 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. – idbrii Mar 24 '11 at 16:59
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.

Jeremy Stein
  • 19,171
  • 16
  • 68
  • 83
raven
  • 18,004
  • 16
  • 81
  • 112
  • 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 Oct 29 '08 at 03:26
  • 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 ) – gnud Dec 11 '08 at 00:58
  • 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 May 24 '09 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 Sep 09 '09 at 06: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. – system PAUSE Sep 15 '09 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'... – Kurt Pfeifle Aug 07 '10 at 18:39
  • Is there any way to detect in the script that it was started with a double-click vs. the command line? – Lance Fisher Dec 23 '10 at 08:12
  • @Lance: not that I'm aware of. – raven Dec 23 '10 at 17:18
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.

jeb
  • 78,592
  • 17
  • 171
  • 225
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
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%
Helen
  • 87,344
  • 17
  • 243
  • 314
SqlACID
  • 4,024
  • 20
  • 28
17

Integer arithmetic:

> SET /A result=10/3 + 1
4
Chris Noe
  • 36,411
  • 22
  • 71
  • 92
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.

demoncodemonkey
  • 11,730
  • 10
  • 61
  • 103
doekman
  • 18,750
  • 20
  • 65
  • 86
15

Output a blank line:

echo.
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
15

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

if foo if bar baz
  • 1
    This is really just a shortcut for nesting ifs: `if foo ( if bar ( baz ) )` (Imagine newlines after the brackets.) – idbrii Mar 24 '11 at 17:04
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.

RealHowTo
  • 34,977
  • 11
  • 70
  • 85
  • 1
    That's an ANSI DOS file - ASCII is 7bit/char. – MarkJ Apr 01 '10 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 Sep 28 '10 at 09:41
14

if block structure:

if "%VS90COMNTOOLS%"=="" (
  echo: Visual Studio 2008 is not installed
  exit /b
)
Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • 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. – Duncan Smart Mar 10 '09 at 16:08
  • You also can't use labels there (which includes those :: style comments) because it will prematurely end the if statement. – Coding With Style Sep 05 '09 at 21:44
  • 2
    @Duncan: You shouldn't use the pseudo-variable `%ERRORLEVEL%` anyway; that's what `if errorlevel ` is for. And *that* does in fact work in such blocks. – Joey Mar 11 '10 at 16:39
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
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
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
  • 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 Nov 04 '08 at 20:48
  • 2
    http://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... – ℳ  . Apr 13 '10 at 05:57
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 ?

Terry
  • 6,160
  • 17
  • 16
MoreThanChaos
  • 2,054
  • 5
  • 20
  • 40
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.

10

Total control over output with spacing and escape characters.:

echo.    ^<resourceDir^>/%basedir%/resources^</resourceDir^>
idbrii
  • 10,975
  • 5
  • 66
  • 107
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    How does that work? The dot demarcates the beginning of the text output? – Chris Noe Oct 29 '08 at 00:54
  • 3
    "echo. x" will output "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 Oct 29 '08 at 00: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 Nov 06 '10 at 00:35
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
Helen
  • 87,344
  • 17
  • 243
  • 314
remonedo
  • 27
  • 3
  • 2
    Surely DATE /T returns 29/10/2008 in Europe and 10/29/2008 in the US... so some localisation may be required! ;-) –  Oct 29 '08 at 15:23
  • That's right! But you can abuse the date command to find out which date format is used. – remonedo Oct 30 '08 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. – Coding With Style Jul 06 '09 at 17:52
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
Lara Dougan
  • 791
  • 4
  • 13
  • 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. – Joey May 29 '09 at 23:49
  • 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. – Coding With Style Jul 03 '09 at 06:57
  • True, this does need delayed expansion, but you can enable it within your script. I am updating my answer now to include that. – Lara Dougan Oct 23 '09 at 12:17
  • 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. – Coding With Style Jun 08 '11 at 15:06
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:\>
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
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)

Community
  • 1
  • 1
matt wilkie
  • 17,268
  • 24
  • 80
  • 115
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.

Coding With Style
  • 1,692
  • 1
  • 14
  • 10
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.

Coding With Style
  • 1,692
  • 1
  • 14
  • 10
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
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
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!

  • 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. – aphoria Oct 31 '08 at 13:42
  • 1
    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. – Chris Noe Oct 31 '08 at 16:48
  • use 'alt+space e p' to paste clipboard at caret position dragging a folder from explorer to cmd window puts directory name at caret position – mr calendar Jan 13 '09 at 18:45
  • You can script it with reg add HKCU\Console /v QuickEdit /t REG_DWORD /d 1 /f – Shea Jul 03 '09 at 00:03
  • 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... ;) – demoncodemonkey Sep 10 '09 at 20:46
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
Community
  • 1
  • 1
Andy Morris
  • 3,393
  • 1
  • 21
  • 20
4

The subdirectory option on 'remove directory':

rd /s /q junk
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
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.

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 ...
reuben
  • 3,360
  • 23
  • 28
  • Sadly, SHIFT does not effect the value of %*, it only modifies the values of the individual params: %1, %2, etc. – Chris Noe Dec 30 '08 at 18:23
  • Right. That's still possibly useful in some cases, but I agree that it's inconsistent... – reuben Dec 30 '08 at 18:40
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.

NicJ
  • 4,070
  • 1
  • 25
  • 18
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.

Igor Dvorkin
  • 827
  • 1
  • 8
  • 18
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

Helen
  • 87,344
  • 17
  • 243
  • 314
Alin Sfetcu
  • 542
  • 6
  • 16
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
)
Philibert Perusse
  • 4,026
  • 5
  • 24
  • 26
  • 1
    SET /P is usually better for this. – Coding With Style Jul 05 '09 at 04:29
  • 1
    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. – Philibert Perusse Jul 10 '09 at 11:51
  • 1
    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. – Coding With Style Jul 11 '09 at 18:41
  • 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. – Philibert Perusse Mar 18 '10 at 18:36
  • :-/ 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. – Coding With Style Jun 10 '10 at 20:53
  • 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. – Philibert Perusse Jun 23 '10 at 12:27
  • 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. – Coding With Style Feb 08 '11 at 22:00
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%
Dov
  • 15,530
  • 13
  • 76
  • 177
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.

NicJ
  • 4,070
  • 1
  • 25
  • 18
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.

raven
  • 18,004
  • 16
  • 81
  • 112
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.

Dean Rather
  • 31,756
  • 15
  • 66
  • 72
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.

JUST MY correct OPINION
  • 35,674
  • 17
  • 77
  • 99
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.

ConcernedOfTunbridgeWells
  • 64,444
  • 15
  • 143
  • 197
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"
Brecht Yperman
  • 1,209
  • 13
  • 27
2

Findstr with regular expression support:

findstr "^[0-9].*" c:\windows\system32\drivers\etc\hosts
BartekB
  • 8,492
  • 32
  • 33
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>
2

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

dir /b *.* | findstr /f:/ "thepattern"
Frans Bouma
  • 8,259
  • 1
  • 27
  • 28
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%
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.

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.

Coding With Style
  • 1,692
  • 1
  • 14
  • 10
1

Setting environment variables from a file with SET /P

SET /P SVNVERSION=<ver.tmp
Anton Tykhyy
  • 19,370
  • 5
  • 54
  • 56
1

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

CMD /C EXIT number
Coding With Style
  • 1,692
  • 1
  • 14
  • 10
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
Chris Noe
  • 36,411
  • 22
  • 71
  • 92
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*").

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
RealHowTo
  • 34,977
  • 11
  • 70
  • 85
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
Chris Noe
  • 36,411
  • 22
  • 71
  • 92
PabloG
  • 25,761
  • 10
  • 46
  • 59
  • Actually, :: Is a special case of a label, and not a comment. See http://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. – Precipitous Sep 22 '10 at 00:19
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)
Helen
  • 87,344
  • 17
  • 243
  • 314
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
  • 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? – Mark Allen Dec 30 '10 at 23:09
  • 1
    It will end up calling DOS (int 0x21) function 0x0A which read from the standard input. Disassembly [link](http://pastie.org/1707647) NB. The .com file will not work in 64-bit versions of Windows. – Jonas Engström Mar 24 '11 at 10:21
1

List all drives:

fsutil fsinfo drives
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
dave1010
  • 15,135
  • 7
  • 67
  • 64
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.

Fadrian Sudaman
  • 6,405
  • 21
  • 29
1

Bail on error.

IF "%errorlevel%" NEQ "0" (
   echo "ERROR:  Something broke.  Bailing out."
   exit /B 1
)
caseyboardman
  • 799
  • 2
  • 11
  • 26
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.)

Soulman
  • 2,910
  • 24
  • 21
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!
DaWolfman
  • 79
  • 8
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
bneal
  • 166
  • 5
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.

MadKat
  • 1
  • 1
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.

Coding With Style
  • 1,692
  • 1
  • 14
  • 10
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.

sahmeepee
  • 378
  • 2
  • 8
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.

guerda
  • 23,388
  • 27
  • 97
  • 146
0

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

for /l %i in (1,1,10) do echo %i
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
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.

RWendi
  • 1,446
  • 5
  • 20
  • 38
  • 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) – Coding With Style Jul 05 '09 at 04:34
  • 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 :) – demoncodemonkey Sep 10 '09 at 20:54
  • 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." – Coding With Style Mar 03 '10 at 02:33
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.

Mark Arnott
  • 1,975
  • 3
  • 17
  • 28
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.

Philibert Perusse
  • 4,026
  • 5
  • 24
  • 26
  • 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. – Coding With Style Jul 05 '09 at 04:36
  • 1
    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! – Philibert Perusse Jul 10 '09 at 12:03
0

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

set > test
dir test
del test
some
  • 48,070
  • 14
  • 77
  • 93
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
Sascha
  • 1,410
  • 2
  • 10
  • 10
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.

John Fisher
  • 22,355
  • 2
  • 39
  • 64
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

jon_brockman
  • 373
  • 1
  • 11
  • You can do the same thing with shortcuts. And I highly recommend [Launchy](http://www.launchy.net) if you like to launch things this way. It can become + (or whatever shortcut you want) --> , . – P Daddy Mar 24 '11 at 18:55
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
jftuga
  • 1,913
  • 5
  • 26
  • 49
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 :)
Deniz Zoeteman
  • 9,691
  • 26
  • 70
  • 97
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.

leander
  • 8,527
  • 1
  • 30
  • 43
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.

Community
  • 1
  • 1
Mashmagar
  • 2,556
  • 2
  • 29
  • 38
  • 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-meister – Chris Noe Feb 22 '12 at 13:53
-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

jftuga
  • 1,913
  • 5
  • 26
  • 49
-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 <MuldeR2@GMX.de>
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')
-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=
Helen
  • 87,344
  • 17
  • 243
  • 314
cookre
  • 705
  • 1
  • 5
  • 7
  • 6
    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. – Coding With Style Jul 05 '09 at 23:30