Top 10 DOS Batch tips (Yes, DOS Batch...)

 

PowerShell's great. I'm fired up about the opportunity to use .NET objects from simple scripts. I'll admit I'm still getting up to speed with it, but I'm totally sold on PowerShell.

However, it's not installed on a lot of servers I work with, and I still do a lot of my "clumsy developer attempting DBA and network admin" tasks from DOS Batch files. You can do quite a bit with DOS Batch - the silly fact is the my most popular posts (by a huge margin) are some batch scripts to allow running IE7 and IE6 on the same computer.

So, by way of tribute to the dying art of the DOS Batch file, I present my top ten batch file tricks:

  1. Use PUSHD / POPD to change directories
    Read Scott Hanselman's writeup on PUSHD. The basic idea is that it keeps a stack, so at the simplest level you can do something like this:
    PUSHD "C:\Working Directory\" ::DO SOME WORK POPD

    That allows you to call the batch file from any directory and return to the original directory when you're done. The cool thing is that PUSHD can be nested, so you can move all over the place within your scripts and just POPD your way out when you're done.
  2. Call FTP scripts
    This sample prompts for the username and password, but they can of course be hardcoded if you're feeling lucky.
    set FTPADDRESS=ftp.myserver.com set SITEBACKUPFILE=FileToTransfer.zip set /p FTPUSERNAME=Enter FTP User Name: set /p FTPPASSWORD=Enter FTP Password: CLS > script.ftp USER >>script.ftp ECHO %FTPUSERNAME% >>script.ftp ECHO %FTPPASSWORD% >>script.ftp ECHO binary >>script.ftp ECHO prompt n :: Use put instead of get to upload the file >>script.ftp ECHO get %SITEBACKUPFILE% >>script.ftp ECHO bye FTP -v -s:script.ftp %FTPADDRESS% TYPE NUL >script.ftp DEL script.ftp
  3. Read from the registry
    You can make creative use of the FOR command to read from and parse a registry value (see my previous post for more info).
    FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL" /v SQL2005') DO SET SQLINSTANCE=%%B
  4. Run SQL Commands
    You can call OSQL (or SQLCMD on servers with SQL 2005 installed) to execute SQL commands:
    osql -E -d master -Q "BACKUP DATABASE [%DATABASENAME%] TO DISK = N'D:\DataBase\Backups\%DATABASENAME%_backup' WITH INIT , NOUNLOAD , NAME = N'%DATABASENAME% backup', NOSKIP , STATS = 10, NOFORMAT"
  5. Check if a file or folder exists
    I used this to do a quick and dirty check to see if a Windows Hotfix had been installed in my IE7 Standalone scripts:
    IF EXIST %SystemRoot%\$NtUninstallKB915865$\ GOTO KB_INSTALLED ECHO Installing Hotfix (KB915865) to allow tab support START /D "%~dp0/Installation/Update/" xmllitesetup.exe
  6. Pause execution for a number of seconds
    There are different ways to do this from within a batch file, all with their tradeoffs. I use a ping to an invalid IP address with a timeout. The best way to do this is to find an invalid IP address and then pint it, but 1.1.1.1 is a pretty safe bet:
    ECHO Waiting 15 seconds PING 1.1.1.1 -n 1 -w 15000 > NUL
  7. Use defaults for optional parameters
    It's not really easy to check for a missing parameter. You have to use something like "IF dummy==%1dummy", which will only be true if %1 is empty. So, for example, here we're allowing a user to supply an application path via the third parameter, and defaulting it if it's missing. By the way, beware the IF syntax. The line spacing makes a difference, so this is one that I just copy and paste to avoid figuring it out every time.
    IF dummy==dummy%3 ( SET APPLICATIONPATH="C:\Program Files\MyApp\" ) ELSE ( SET APPLICATIONPATH = %3 )
  8. Process each file matching a pattern in a directory
    I previously posted a script which iterates all files named *.bak in a directory and restores them on the local instance of SQL Server. Here's an excerpt:
    PUSHD %BACKUPDIRECTORY% FOR %%A in (*.bak) do CALL :Subroutine %%A POPD GOTO:EOF :Subroutine set DBNAME=%~n1 ::RUN SOME OSQL COMMANDS TO RESTORE THE BACKUP GOTO:EOF
  9. Use batch parameter expansion to avoid parsing file or directory info
    Batch file parameters are read as %1, %2, etc. DOS Command Extensions - available on Windows 2000 and up - add a lot of automatic parsing and expansion that really simplifies reading filenames passed in as parameters. I originally put this at the top of the list, but I moved it because I figured the insane syntax would drive people off. I wrote a simple batch script that shows some examples. I think that makes it a little more readable. Stick with me, I think this is one of the best features in DOS batch and is worth learning.

    First, here's the batch file which just echos the processed parameters:
  10. @echo off echo %%~1 = %~1 echo %%~f1 = %~f1 echo %%~d1 = %~d1 echo %%~p1 = %~p1 echo %%~n1 = %~n1 echo %%~x1 = %~x1 echo %%~s1 = %~s1 echo %%~a1 = %~a1 echo %%~t1 = %~t1 echo %%~z1 = %~z1 echo %%~$PATHATH:1 = %~$PATHATH:1 echo %%~dp1 = %~dp1 echo %%~nx1 = %~nx1 echo %%~dp$PATH:1 = %~dp$PATH:1 echo %%~ftza1 = %~ftza1



    Now we'll call it, passing in "C:\Windows\Notepad.exe" as a parameter:
    C:\Temp>batchparams.bat c:\windows\notepad.exe %~1 = c:\windows\notepad.exe %~f1 = c:\WINDOWS\NOTEPAD.EXE %~d1 = c: %~p1 = \WINDOWS\ %~n1 = NOTEPAD %~x1 = .EXE %~s1 = c:\WINDOWS\NOTEPAD.EXE %~a1 = --a------ %~t1 = 08/25/2005 01:50 AM %~z1 = 17920 %~$PATHATH:1 = %~dp1 = c:\WINDOWS\ %~nx1 = NOTEPAD.EXE %~dp$PATH:1 = c:\WINDOWS\ %~ftza1 = --a------ 08/25/2005 01:50 AM 17920 c:\WINDOWS\NOTEPAD.EXE



    As I said, the syntax is completely crazy, but it's easy to look them up - just type HELP CALL at a DOS prompt; it gives you this:

    %~1 - expands %1 removing any surrounding quotes (")
    %~f1 - expands %1 to a fully qualified path name
    %~d1 - expands %1 to a drive letter only
    %~p1 - expands %1 to a path only
    %~n1 - expands %1 to a file name only
    %~x1 - expands %1 to a file extension only
    %~s1 - expanded path contains short names only
    %~a1 - expands %1 to file attributes
    %~t1 - expands %1 to date/time of file
    %~z1 - expands %1 to size of file
    %~$PATH:1 - searches the directories listed in the PATH environment variable and expands %1 to the fully qualified name of the first one found. If the environment variable name is not defined or the file is not found by the search, then this modifier expands to the empty string

    The modifiers can be combined to get compound results:

    %~dp1 - expands %1 to a drive letter and path only
    %~nx1 - expands %1 to a file name and extension only
    %~dp$PATH:1 - searches the directories listed in the PATH environment variable for %1 and expands to the drive letter and path of the first one found.
    %~ftza1 - expands %1 to a DIR like output line

    In the above examples %1 and PATH can be replaced by other valid values. The %~ syntax is terminated by a valid argument number. The %~ modifiers may not be used with %*

  11. Learn from the masters
    By far, my favorite resource for DOS Batch trickery is the Batch Files section of Rob van der Woude's Scripting Pages. He's got some good PowerShell resources, too.

What about you? Got any favorite DOS Batch tricks?

59 Comments

  • PUSHD and POPD are great. An additional advantage over CD is the fact that including a drive letter changes to the drive and directory specified whereas CD just changes the active directory on the specified drive.

    If you use them a lot you can save a fair bit of typing by defining two one-line command files +.cmd and -.cmd somewhere on your path. They simply contain;

    +.cmd
    @pushd %1

    -.cmd
    @popd

    Now you can just run + to enter a directory and - to return.

  • one more that I just recalled, from reading Steve's comment

    cd /d

    changes both, the directory and the drive letter

  • Very good!
    And this tip: "Pause execution for a number of seconds" Gosh! Why didn't I think of it before?
    Thanks for all these tips!

    []'s

    Cleydson

  • @oscar - The sleep command isn't available on a default install. It's part of the Windows 2003 Resource Kit, which is a separate download.

  • I love using the findstr.exe that is built into Windows XP and later... it's closer to "grep" than the original "find" and the built in ability to search subdirectories is a real gift.

    Andrew.

  • Tip #8 "Use batch parameter expansion to avoid parsing file or directory info" was just what I was looking for!

    So what if the syntax is "insane"? (No more so, than, say, printf formatting syntax in C.)

    Anyway it's easy to copy/paste what I want from your page, or, as you taught me, from CALL HELP at DOS command prompt.

    I think it should be tip #1 again ...

  • Oops. I meant

    Tip #9 "Use batch parameter expansion to avoid parsing file or directory info" was just what I was looking for!

  • how do i put a automatic yes in (Y/N)option

  • @filipo111

    echo N | del .

  • Great tips!

    How do I use xcopy to search for and copy say, word files, scatterded over a drive. Also if none present then move on to next command. Right now I have:

    X:\XCOPY.exe C:\*.doc "X:\Word Files" /s/e/v/i/y/h

    This command string copies the file directory structure which takes forever and something I do not want. Just looking to pin point files (ie word or microsoft money - *.mny) and copy them.

    Thanks, Matt

    mstanchi@yahoo.com

  • Pause for x number of seconds:
    ping -n x localhost

  • Hi,

    I'm trying to automatically run a .reg file through a batch file, but need to find out how the "Yes/No" and "OK" pop ups can be avoided and automatically accepted so the user doesn't have to click on Yes and OK everytime.

    example of my batchfile; let's say the .bat file is located on the X-drive:

    x:
    Permission_Required_0.reg

    Thanks in advance, if anybody is able to help me out!

    Dom

  • Dom,

    To get a Reg file put in without the Popup
    try this

    regedit /s file.reg


    >Hi,
    >
    >I'm trying to automatically run a .reg >file .through a batch file, but need to find >out how the "Yes/No" and "OK" pop ups can be >avoided and automatically accepted so the >user doesn't have to click on Yes and OK >everytime.
    >
    >example of my batchfile; let's say the .bat >file is located on the X-drive:
    >
    >x:
    >
    >Permission_Required_0.reg

    >Thanks in advance, if anybody is able to help >me out!
    >
    >Dom


  • How do i output any errors to a txt file so i can see which ftp's failed?

  • Is there a way to get the Current file name in the batch file?

    I am running a batch file: testing123.bat

    Is there a way to get "testing123.bat" in a variable?
    I use %date% and %time% but have not found a way to pick up the currently running file name.
    Thanks
    Frank

  • @Frank, try using %0.

  • Any ideas how I could extract a string from a %
    1 parameter, eg: reading "123" or "45" from "12345"?

    Thanks,
    Jamie

  • @Jamie
    try
    set test=12345
    echo %test:~0,3%
    echo %test:~3,2%

  • Hey guys, total bat noob here. I've got a dilemma that seems straightforward to me, but bumbling through it has been anything but. I have a drive mapped to a remote server (Z drive) and a duplicate drive on my local (called “S”). Right now, like a chump, I’m busy manually copying back and forth files that get updated (since the soft I'm working with needs these objects in their proper dirs). What sort of commands would I use where I could select 1 or more files that have been newly created on the mapped "Z" and right click and tell it to copy local to my mirrored directory (and automatically building the folder tree if it doesn’t exist)? I think I've found out how to add things to the windows right click context menu, but I can't figure out how to pass the name and directory of selected files to a cmd prompt! Great tips BTW, and thanks in advance anyone for help! (Oh, and the files are 100mb+ and scattered among 100's of dir's, so syncing programs aren't too useful to me. I get an update that a certain file is changed by the client and I hand copy individually. Only way to do it while keeping bandwidth overhead to a minimum.)

  • Noob - call robocopy from your batch file, it just works.

  • Regarding "9: Use batch parameter expansion..."

    One other thing to note is that it can be combined into a "for" statement to do lots of magic:
    for %I in (text.txt) do echo %I is %~zI bytes
    for %I in (test.bat) do echo: %~$PATH:I

    This one seems to only work for UPPERCASE, single-letter variable names, and only for those at the start of the alphabet. Your mileage may vary.

  • Hi Jon, In #3 "Read from the registry", you mention a previous post in reference to "creative use of the FOR command". I looked through your archives, and can't find the one you're talking about. Do you remember which it is? thanks! Rob

  • Hi, Joel Noob Try xcopy, I think it will do what you want. It even has an exclude list included :)


  • Hi,

    Is it possible to open a 'browse for file' window from a batch script, select a file and then inject the path/name of that choosen file back into the script ?

  • Is there any way to delete all files and sub-folders (may with files too) of a given folder?

  • how do I remove the quotes from a passed parameter?

    eg:-
    batchfile has the line --> echo %1 moon
    call it with batchfile.bat "over the "

    and the result is:-
    "over the "moon

    One needs the quotes to get the variable but then the variable includes the quotes!


  • oops... found it:-

    %~1 - expands %1 removing any surrounding quotes (")

    echo %~1 moon
    Works fine.

    Thanks for making this info available.


  • Nice blog. Very healthy discussion.

    To upload using FTP an entire folder full of files and subfolders, try this script.

    http://www.biterscripting.com/helppages/SS_FTPUpload.html

    It even creates subfolders as necessary. Will mirror the entire local folder to the FTP server.

  • Hello
    set PATH_VER=c:\folder1\folder2\folder3\file.bat

    In "file.bat", I whould like to obtain the string "c:\folder1"
    I mean how to get up two level from the location of the file.bat ?

    I used %~dp0 , %~dp1 (twice) but I didn't succeed to do it properly

    Any Idea?
    Thank you

  • I have a little problem that I cannot solve. I have a part solution but need a little help to finish it off!

    My first (successful) step was to create a batch file that reads a plain text file (directory.txt) that contains the name of a new directory that I want creating, then the batch file creates it.

    e.g. in the "directory.txt" file ...

    My New Directory Name
    (no quotes in the file)

    Batch file:

    FOR /f "tokens=*" %%n IN (directory.txt) DO MKDIR "%%n"

    The reason for doing this is that the directory name can contain spaces, and enclosing the string in quotes does not work for MKDIR in a batch file. It works at a prompt, but not batch.

    Now what I want to achieve is to pass the full directory name to the batch file as an argument %1, but I cannot figure out how to replace the "IN (directory.txt)" with an appropriate entry using the %1. How do I do that?

    Thanks.

  • Any ideas how I could extract a string from a %1 parameter, eg: reading "123" or "45" from "12345"?

    Again, from a parameter, not from a variable!!


    Thanks in advance

  • Hi again:

    Any ideas how i could trim some string from a parameter (like %1)

    I need the following behaviour using "%1" instead of "%variable%":

    set dummy=-test
    echo.%dummy:-=%

    The prompt output is:
    test (without the "-")


    THX!!


  • echo N | del is not working

  • How do I display empty line from batch file?

  • to all those asking how to apply the text replacement or extraction to a parameter: just assign it to a variable and then use the instructions as abive
    set param1=%1
    echo.%dummy:-=%


  • > Top 10 DOS Batch tips (Yes, DOS Batch...)
    ...only, it's not DOS batch! It's Windows batch!

  • Great page!
    Personally, I can't live without this one:

    Echoing text without a newline at the end, e.g. to print 'Calculating ... ' and then after the calculation complete the line with 'OK' or 'FAIL'.
    Can be done like this:

    echo.|set /p ="Calculating ... "
    rem Calculation
    echo OK

    I use this often, so I have a 'subroutine':

    CALL:Write "Calculating ... "
    ...
    goto :EOF

    :Write
    echo.|set /p =%1
    exit /b 0

    Cheers!

  • What about the CHOICE.com command?

    I like that it has a default choice you can set in case your user is an induhvidual.

    CHOICE /T:N,5 "Choose all ready! "

    If they don't choose after 5 seconds, it chooses "N" for them.

    CHOICE /C:ABCDEFGHIJKLMNOPQRSTUVWXYZ "Choose a letter of the alphabet or menu choice. "

    It's a pretty handy command.

  • Should have added that you check errorlevel, high value to low, right after the choice to branch to the code they selected.

    Handy way for a program to "sleep", with a secret override.

    This batch quietly waits 99 seconds before processing normally. Unless you hit "X"!!!

    @echo off
    choice /n /c:YNX /t:y,99
    if errorlevel==3 goto dalek
    if errorlevel==2 goto end
    if errorlevel==1 goto cont
    :cont
    echo Normal processing after a 99 second wait.
    goto end
    :dalek
    echo -
    echo EXTERMINATE! EXTERMINATE!
    echo -
    :end

  • Is it possible to split a file in half using only DOS commands?

  • If I want to split a long list in half, I could alter this DOS TAIL batch, to divide %counter% by 2 to get the second half of the file, using 'skip'in FOR/IN/DO, but how can I get just the first half?
    -----------------------------
    @echo off
    echo -tail-
    set /p file2split="Enter filename ... "
    for /f %%p in (%file2split%) do call :count
    set /a theselines=%counter%-10
    for /f "skip=%theselines% tokens=1*" %%p in (%file2split%) do echo %%p %%q >> tail.txt
    start notepad tail.txt
    goto :eof
    :count
    set /a counter=%counter%+1
    goto :eof
    -------------------

    gotta be some trick to do it....

  • Thanks, your tips have helped me solving a nested batch call issue wrt quotes.

  • Just found this article and was finally able to find a decent alternative to the UNIX 'which' command I was looking for. Here's a sample batch I created using the %$PATH:1 expansion:

    -----------------------
    @echo off
    SET EXENAME=Notepad.exe

    CALL :WHICH "%EXENAME%"
    SET EXEPATH=%RET%

    IF EXIST %EXEPATH% (
    echo EXEPATH=%EXEPATH%
    call "%EXEPATH%"
    ) ELSE (
    echo %EXENAME% not found!
    )

    GOTO :EOF

    :WHICH
    SET RET=%~$PATH:1
    GOTO :EOF

    ---------------------
    Output:
    ---------------------
    EXEPATH=C:\WINDOWS\system32\notepad.exe

    *Notepad.exe launches*

  • greate, in the period of apps some things we can
    do only and simple with a .bat file

  • Hi. excellent article. Sad that it becomes spammed in the comments. But I mean.. after 6 years ! ;)
    Regarding "9: Use batch parameter expansion..."
    Someone might be reading, I need help :
    I give a wildcard as parameter, but when I use %~n it resolved it.
    Eg : %1 = c:\temp\blah*.log
    %~dp1= c:\temp (OK)
    %~x1 = .log (OK)
    %~n1 = blah1stfileinfolder.log (NOK for me, I want blah*)

    Thanks

  • Go to my review webpage..

  • b0c4m341

    goi8gh4n

    f39s020t9d

    x7l9e591

    umvbai8v

  • c6haz19j

    uh737dv5

    f39s020t9d

    d0udbgid

    bwl9nvem

  • i68a880s

    rucstco5

    f39s020t9d

    sftm7ax6

    kvh2iogi

  • Anybody have something to strip an apostrophe from a filename?

  • Hi, all the time i used to check weblog posts here in
    the early hours in the morning, as i love to learn more and more.

  • bn571ktd

    myrmvztp

    shgreyryh

    egxj3j96

    filfxhrj

  • My developer is trying to persuade me to move to .
    net from PHP. I have always disliked the idea because of the expenses.
    But he's tryiong none the less. I've been using WordPress on several websites
    for about a year and am anxious about switching to another platform.
    I have heard good things about blogengine.
    net. Is there a way I can import all my wordpress content into
    it? Any help would be really appreciated!

  • pp0ks3bo

    ymb38sf5

    f54yewr4t536

    udnvtq0g

    yo738hpf

  • x08w537q

    sttiumd2

    f54yewr4t536

    a9w1tp8y

    y9goyy1l

  • agdli2uy

    x2l5dsxf

    f54yewr4t536

    lmkvskpx

    na16qsvy

  • wcble37a

    sw7apybh

    f54yewr4t536

    m1n2vvwa

    rxk44wr1

  • Everything is very open with a really clear explanation of
    the issues. It was really informative. Your website is very useful.
    Many thanks for sharing!

  • Hello i am kavin, its my first time to commenting anyplace,
    when i read this paragraph i thought i could also create comment due to this good piece of writing.

Comments have been disabled for this content.