DOS

WARNING: If you want to learn to write batch script in DOS, stop it right now! Do yourself a favor. Stop reading this tutorial. Unless your are masochist. Please consider other alternative such as Perl. DOS is a pain and the 'language' is not intuitive and not logical.

ECHO

Display string.

REM Display "This is a string."
ECHO This is a string.

REM Escape special character using ^
REM Display ampersand(&)
ECHO ^&

SETLOCAL, ENDLOCAL

SETLOCAL: Localise environment variables under SETLOCAL. ENDLOCAL: Restore previous environment variables that are set before SETLOCAL.

@ECHO OFF 

REM Value1
SETLOCAL
SET value=1
ECHO %value%

REM Value2
SETLOCAL
SET value=2
ECHO %value%

REM Value3
SETLOCAL
SET value=3
ECHO %value%

REM Back to Value2
ENDLOCAL
ECHO %value%

REM Back to Value1
ENDLOCAL
ECHO %value%

Useful Stuff

CALL
Run another batch file.
cls
Clear MS-Prompt screen.
&
By adding &, you can write multiple instructions on the same line. It will execute instructions sequentially from left to right.
ECHO Hello & ECHO Hello Again
&&
Will run the command after && only if the command before && was completed successfully.
ECHO Hello && ECHO I will only run if the previous command was completed successfully.

Comment

::
DOS will not execute any batch file line with twin colons in front of it, nor display it on the monitor screen. After seeing the second colon, DOS ignores anything following and goes to the next line. That is because the colon is an illegal label character.
:: This line is a comment.
REM or @REM
REM stands for Remark. DOS does not execute lines starting with REM, but it does read them.
REM This line is also a comment
@REM Adding @ in front of REM will not show this command in the DOS prompt.
&REM or &::
Unfortunately, using :: or REM alone allow you to only comment the whole line. By adding & in front of REM or ::, you can add a comment at the end of your line of instruction.
@ECHO OFF
ECHO Hello1 &:: This is a comment at the end of this line.
ECHO Hello2 &REM This is also a comment at the end of this line.

References

http://www.ss64.com/ http://www.robvanderwoude.com/news.html http://stackoverflow.com/questions/8385454/batch-files-list-all-files-in-a-directory-with-relative-paths

Turn off output

Redirect application to NUL

echo a > NUL

Variable

Set variable To declare a variable, use the following syntax:

SET variablename="value"


Call variable To call the variable, use the following syntax:

SET variablename="Hello"
ECHO %variablename%


Clean variables Always clean up the variable after it is being used.

SET variablename="Hello, world"
ECHO %variablename%
SET variablename=&::
ECHO %variablename%

Reference: http://www.thetechguide.com/howto/2kdos/04-05.html

Assign command result to a variable

for /f "tokens=*" %%a in ('"WHERE notepad.exe"') do set YOURVAR=%%a
echo.%YOURVAR%

Change encoding/code page

@REM Change to UTF-8.
chcp 65001

@REM Create M3U file.
echo #M3UEXT>filename.m3u
dir /b/o *.mp3 >>filename.m3u

Check if input argument exists

@ECHO OFF

@REM Let's assume that you want to check whether or not year input argument exists
SET year=%1
 
IF [%year%]==[] GOTO MISSING_ARGS
 
echo Do something.
echo Do another thing.
 
GOTO THE_END
:MISSING_ARGS
echo ERROR: Year argument is missing! Supply year argument to the batch file.
 
:THE_END
@REM The end. Do nothing. There should be no other statement.

Create an empty file

type NUL > emptyFile.txt

Customize command prompt line

REM Clean Prompt line
prompt $

REM Put Prompt line back to MSFT's default format
prompt $p$g

REM Show date and time: Sun 03/07/201013:16:23.90 <C:\WINDOWS>
prompt $D $T$_$L$P$G
 
prompt --=[$D $T]=--$_$L$P$G
REM Output
REM
REM --=[2014-05-16 10:50:03.77]=--
REM <C:\temp\Xuan\websites\openwritings>

http://kb.iu.edu/data/aamm.html http://www.watchingthenet.com/customize-windows-command-prompt-to-look-like-a-bash-shell-prompt.html

START cmd /k "prompt --=[$D $T]=--$_$L$P$G&& cd C:\temp\"

Directory path of the executed batch file

There are batch files that you put in your environment variables(e.g. PATH) folder so that you can execute them anywhere. However, to know where the batch files were executed, here is the code:

SET BATCH_HOME=%~dp0
ECHO.%BATCH_HOME%

Display relative file path of all files from the current directory

You can call the script below and then filter what you want using find command as follows:

REM Display relative file path of all files from current directory.
REM   Then select file paths that contain ".doc"
CALL relative_file_path.bat | find /I ".doc"
@ECHO OFF
REM Display relative file path of all files from the current directory
SETLOCAL DisableDelayedExpansion
SET "r=%__CD__%"
FOR /R . %%F IN (*) DO (
  SET "p=%%F"
  SETLOCAL EnableDelayedExpansion
  ECHO(!p:%r%=!
  ENDLOCAL
)

Solution from: http://stackoverflow.com/questions/8385454/batch-files-list-all-files-in-a-directory-with-relative-paths

Escape percent symbol

REM To escape the percent symbol, add another percent symbol
convert inputfilena.jpg -threshold 50%% outputfilename.jpg

Extract/Convert audio stream of a video file into MP3

@ECHO OFF
REM Description: Extract/Convert audio stream of a video file into MP3.
REM Requirements: 
REM   -Mplayer / Mencoder / FFmpeg

REM --------------------------OPTIONS-------------------------------
REM mencoder %1 -of rawaudio -oac mp3lame -ovc copy -o "%~n1".mp3

REM Slow: Convert audio stream to MP3.
REM ffmpeg -i %1  -f mp3 "%~n1".mp3
REM ffmpeg -y -i %1 -f mp3 -aq 2 "%~n1".mp3

REM Fast: Dump original audio stream to file.
REM mplayer -dumpaudio %1 -dumpfile "%~n1".mp3
REM mencoder -ss 00:00:00 -endpos 00:01:30 %1 -of rawaudio -oac mp3lame -ovc copy -o "%~n1".mp3
REM ----------------------------------------------------------------
 
FOR /F "delims=" %%W IN ('dir /b *.mp4') DO (
CALL :DO_WORK_IN_LOOP "%%W"
)
GOTO :EOF
 
:DO_WORK_IN_LOOP
  ECHO %time% >> elapse.txt
  ECHO %1 >> elapse.txt
  ffmpeg -i %1  -f mp3 "%~n1".mp3
  ECHO %time% >> elapse.txt
  ECHO ------------------------>> elapse.txt
  GOTO :EOF

Note: http://oss.netfarm.it/mplayer-win32.php http://ffmpeg.arrozcru.org/ http://ffmpeg.org/trac/ffmpeg/wiki/Encoding%20VBR%20%28Variable%20Bit%20Rate%29%20mp3%20audio

Fast way to delete a lot of files and folders

del /f/s/q foldername > nul
rmdir /s/q foldername

The first line is to delete files and output to nul to avoid the overhead of writing to screen for every singe deleted file. The second line is to delete the remaining directory structure.

Generate a M3U file per folder

REM Description: Generate a M3U file per folder.
REM   -You need to change "C:\Your\MP3\folder\path\" to match your folder path.
REM   -Multilingual is limited by DIR command.
REM Requirements: -You need SED installed.
 
FOR /R "C:\Your\MP3\folder\path\" %%G IN (.) DO (
CALL :Create_M3U "%%G"
)
ECHO "Other commands here after the loop."
 
GOTO :EOF
 
:Create_M3U
  PUSHD %1

  REM Format the directory name.
  ECHO %1 > tmpfile.txt
  sed -i "s/\\\.//" tmpfile.txt
  sed -i "s/.*\\//" tmpfile.txt
    REM Clean up directory name.
    sed -i "s/ //g" tmpfile.txt
    sed -i "s/-//g" tmpfile.txt
    sed -i "s/,//g" tmpfile.txt

  REM Assign directory name to a variable to be used.
  sed -i "s/$/\.m3u/g" tmpfile.txt
  SET /p m3uFilename= < tmpFile.txt

  REM Create M3U file with a list of *.mp3
  ECHO #EXTM3U > %m3uFilename%
  REM DIR /s/b/o *.mp3 >> %m3uFilename%
  CALL relative_file_path.bat | find /i ".mp3" >> %m3uFilename%

  REM Add absolute directory path to MP3 filename
  REM sed -i "s/^/%1/" %m3uFilename%
  
  REM Clean up
  DEL /q tmpfile.txt
  DEL /q sed??????
  POPD
 
  GOTO :EOF

Loops

Infinite loop using GOTO

@ECHO OFF
 
:Loop
 
ECHO Infinite loop. Ctrl+c to stop.
 
GOTO Loop

Conditional loop using GOTO

@ECHO OFF

REM LOOP 10 times.
SET Max=10
SET i=0
 
 
:Loop
REM If i is greater than 10, then get out of this loop.
IF %i% GTR %Max% GOTO GetOut
 
ECHO %i%

REM Increment i.
SET /A i=i+1
 
GOTO Loop
 
 
:GetOut
REM Clean up variables.
SET Max=&::
SET i=&::
 
ECHO continue processing...

FOR loop in a set

REM Loop through a defined set.
@ECHO OFF
FOR %%W IN (a B C d E whatever) DO (
ECHO %%W
)

REM ========================= OR =========================

REM Loop through each line returned by DIR command.
REM By default, the delimiter is a space. Therefore, it will not properly handle filenames with spaces.
REM To avoid this issue, use "delims=" to set the delimiter to nothing. Afterward, it will take the complete line.
FOR /F "delims=" %%W IN ('dir /s/b *.*') DO (
ECHO %%W
)

REM ========================= OR =========================

REM Use FOR loop to loop X times.
REM Syntax: FOR /L %variable IN (start,step,end) DO
FOR /L %%V IN (1,1,20) DO (
ECHO %%V
)

REM ========================= OR =========================
REM Example using token and delimiter
REM time command will output "The current time is: HH:MM:SS.mm".
REM "HH:MM:SS.mm" is the 5th token in the time command.
FOR /F "tokens=5 delims= " %%i IN ('echo ^| time ^| find "current" ') DO (
ECHO %%i
)

Can't increment environment variables within the FOR loop

DOS doesn't increment environment variables within the FOR loop. However, you can call a subroutine outside of the FOR loop and do your increment there, like this:

@ECHO OFF
 
SET i=1
FOR /L %%V IN (1,1,3) DO (
REM Will always be 1.
ECHO In Loop: %i%

REM Call Increment subroutine outside of the FOR loop.
CALL :Increment
)
 
ECHO "Other commands here after the loop."
 
GOTO :EOF
 
:Increment
  ECHO ___________Out of Loop: %i%
  SET /a i+=1
  GOTO :EOF

Note: SET /A does integer arithmetic only.

Opening a new command prompt window within a batch script

@REM Open a new window & display "Hello, world".
START cmd /k "echo Hello, world"

@REM Open a new window & execute multiple line of commands".
START cmd /k "echo Hello, world && echo How are you?"

@REM Open a new window and customize the pre-defined command line.
START cmd /k "prompt --=[$D $T]=--$_$L$P$G"

Padding zeros

@ECHO OFF
 
SET i=1
FOR /L %%V IN (1,1,1003) DO (
CALL :Increment
)
 
ECHO "Done showing zero padding."
 
GOTO :EOF
 
:Increment
  REM Padding zeros
  SET filename=%i%
  if %i% lss 1000 set filename=0%i%
  if %i% lss 100 set filename=00%i%
  if %i% lss 10 set filename=000%i%
 
  ECHO %filename%.txt
 
  SET /a i+=1
  GOTO :EOF
Output will look like:
....
0889.txt
0890.txt
0891.txt
0892.txt
0893.txt
0894.txt
0895.txt
....

Read input from file

Reading simple input from file

REM Create an input file with data.
ECHO A > filename_test.txt
ECHO B >> filename_test.txt

REM Read input file and display each line.
for /f %%L in (filename_test.txt) do (
    ECHO I found %%L
)

Reading input from file with a delimiter

REM Create an input file with data.
ECHO A,> filename_test.txt
ECHO B C, B>> filename_test.txt
ECHO IP, C, B>> filename_test.txt

REM Read input file and display data of each line up to the 1st occurrence of the delimiter.
REM  In this case, the delimiter is a comma(,).
for /f "delims=," %%L in (filename_test.txt) do (
    ECHO I found %%L
)

Read the complete line from input file

REM Create an input file with data.
ECHO A,> filename_test.txt
ECHO B C, B>> filename_test.txt
ECHO IP, C, B>> filename_test.txt

REM Read and display complete line from input file. 
REM  I define the delimiter to nothing. Therefore, it will read until the end of line of each line in the input file.
for /f "delims=" %%L in (filename_test.txt) do (
    ECHO I found %%L
)

Rename filenames without special characters

REM *******************************************************************************
REM Description: Rename filenames(*.pdf and *.xls) without 
REM               specials characters(e.g. spaces, double underscores).
REM Author: Xuan Ngo
REM Note: Command Prompt's code page is different than Windows' code page. 
REM       Therefore, I switched Command Prompt's code page to be the same 
REM       as Windows' so that I can replace accent characters(e.g. à, é, â, etc ).
REM *******************************************************************************

REM Get all *.pdf and *.xls filenames.
FOR /F "delims=" %%W IN ('dir /b *.pdf *.xls') DO (
CALL :removeChars "%%W"
)
GOTO :EOF
 
 
:removeChars
  REM Get the current code page of the Command Prompt.
  For /F "Tokens=2 Delims=:" %%I In ('Chcp ') Do Set /A _CurCP=%%I
  REM Change code page to 1252
  Chcp 1252
 
  SET filename=%1
  
  REM Remove spaces
  SET filename=%filename: =.%
  REM Remove double underscores.
  SET filename=%filename:__=_%
  SET filename=%filename:._=_%
  SET filename=%filename:à=a%
  SET filename=%filename:â=a%
  SET filename=%filename:é=e%
  SET filename=%filename:è=e%

  REM Rename the filename without the specials characters.
  rename %1 %filename%
  
  REM Change back to the original code page of Command Prompt.
  Chcp %_CurCP%
  GOTO :EOF

Simulate Sleep command

Sleep for 10 seconds.

@ECHO OFF
@REM Make sure to ping a non-existing IP, otherwise ping will exit before the timeout.
@REM Wait for 10 seconds. Note: This is not exactly 10 seconds but close to it.
echo %DATE% %TIME%
PING 1.1.1.1 -n 1 -w 10000 >NUL
echo %DATE% %TIME%

String Manipulation

String Substitution

SET Str="Hello, World"
ECHO %Str%
REM Replace all 'o' with 'X'
SET Str=%Str:o=X%
ECHO %Str%

Substring

REM Get string starting from the 5th position to the end.
SET mySubstring=This String will be cut.
ECHO %mySubstring%
SET mySubstring=%mySubstring:~5%
ECHO %mySubstring%

REM =================== OR ======================

REM Use CALL and SET commands to extract a substring with variable length.
SET start=5
SET length=12
SET string=This long string will be cutted.
CALL SET substring=%%string:~%start%,%length%%%
ECHO %substring%

Take screenshots forever

@ECHO OFF

REM ******************************************************************************
REM Description: This script will take screenshots every 10 seconds forever.
REM              Screenshots are saved into sc_[Date]_[Time].png.
REM              It requires NirCmd.exe(http://www.nirsoft.net/utils/nircmd.html)
REM Author: Xuan Ngo
REM ******************************************************************************
 
 
:Loop
 
SET Unique=%date%_%time%
SET Unique=%Unique:/=.%
SET Unique=%Unique::=.%
SET Unique=%Unique: =%
SET Unique=%Unique:Mon=%
SET Unique=%Unique:Tue=%
SET Unique=%Unique:Wed=%
SET Unique=%Unique:Thu=%
SET Unique=%Unique:Fri=%
SET Unique=%Unique:Sat=%
SET Unique=%Unique:Sun=%
 
echo %Unique%
 
REM Save screenshots every 10 seconds.
nircmd.exe cmdwait 10000 savescreenshot sc_%Unique%.png
 
SET Unique=&::
 
GOTO Loop

Using ECHO command

REM Don't display the command lines.
@ECHO OFF
 
SET username=xuan.ngo

REM Escape < and >.
REM In output.txt: <xuan.ngo@openwritings.net>
ECHO ^<%username%@openwritings.net^>>> output.txt

REM Display an empty line.
ECHO #### Use a dot to display an empty line. ####
ECHO.
ECHO #########################################

Using timestamp as unique filename

Using timestamp as unique filename %date% and %time% environment variables display the date and the time respectively. These environment variables can be used to generate a relatively unique string. Here is an example:

SET Unique=%date%_%time%
SET Unique=%Unique:/=.%
SET Unique=%Unique::=.%
SET Unique=%Unique: =%
SET Unique=%Unique:Mon=%
SET Unique=%Unique:Tue=%
SET Unique=%Unique:Wed=%
SET Unique=%Unique:Thu=%
SET Unique=%Unique:Fri=%
SET Unique=%Unique:Sat=%
SET Unique=%Unique:Sun=%
 
echo %Unique%
 
SET Unique=&::

Variable with value less than 10 placing before the redirection symbol

Variable with value less than 10 placing before the redirection symbol(>>) is causing issue. That is because the end result looks like this: 1>>, 2>>, etc. Here is a good example illustrating the issue:

@ECHO OFF
SET i=1
SET filename=output.txt
del /q %filename%
 
FOR /L %%V IN (1,1,5) DO (
CALL :Increment
)
GOTO :EOF
 
:Increment
  REM Issue: "ECHO is off." is being redirected to your file.
  ECHO %i%>>%filename%
  SET /a i+=1
  GOTO :EOF

To resolve this issue, you have to escape your variable with ^. Here is the correct code.

@ECHO OFF
SET i=1
SET filename=output.txt
del /q %filename%
 
FOR /L %%V IN (1,1,5) DO (
CALL :Increment
)
GOTO :EOF
 
:Increment
  REM To resolve the issue. Escape the index or count with ^
  ECHO ^%i%>>%filename%
  SET /a i+=1
  GOTO :EOF

View memory usage of a running process

@ECHO OFF
:INFINITE_LOOP
 
PING 1.1.1.1 -n 1 -w 60000 >NUL
echo %DATE% %TIME% >> %2
tasklist | find "%1" >> %2
ECHO.>>%2
 
GOTO :INFINITE_LOOP

ECHO %DATE% %TIME% doesn't work in FOR loop

ECHO %DATE% %TIME% doesn't work in FOR loop. Here is an example:

FOR /L %%V IN (1,1,3) DO (
  echo %DATE% %TIME%

  REM Wait 2 seconds
  PING 1.1.1.1 -n 1 -w 2000 >NUL
)

You have to put echo %DATE% %TIME% within a batch file(e.g ShowDateTime.bat) and call it from the loop as follows:

FOR /L %%V IN (1,1,3) DO (
  CALL ShowDateTime.bat

  REM Wait 2 seconds
  PING 1.1.1.1 -n 1 -w 2000 >NUL
)

ShowDateTime.bat contains the following:

echo %DATE% %TIME%