Silly batch file tricks, redirecting stdout into an evironment variable and %~dp0

Some things in batch files seem like they should be so simple, but I'm embarrassed to say how long it took to come up with this little trick. Maybe YOU knew it already, but you should have posted it in your blog so I could have googled it and been done in the 10 seconds it SHOULD have taken me to solve it :-)

In case you ever have wanted to take the console output of a command line tool and capture it in an environment variable, this works. There may be better ways. Thanks to Scott Colestock for helping dig this one up.

setlocal
sometool.exe > temp.txt
set /p TOOLOUTPUT= < temp.txt
del temp.txt
..do something with %TOOLOUTPUT%...
endlocal

Of course when Monad comes out none of this monkey business will be necessary. By the way, I just listened to another great Hanselminutes podcast on Monad that has convinced me to give it a whirl http://www.hanselminutes.com/default.aspx?showID=12.

Since I'm on the topic of useful/(or useless?) batch file tricks, another little known one I find myself using alot is the "%~dp0" macro which resolves to the fully expanded path to the directory containing the batch file. This allows batch files to run regardless of the current working directory. So for example Visual Studio post build events run with the current working directory set to bin\Debug or (bin\Release). But you probably have the postbuild.bat file sitting up a couple directories along side the csproj/vbproj project file. So adding a %~dp0 in front of things you do in the batch file give you location independence without having to do hard-coded paths or a lot of  ..\..'s all over the place. So the following will always find the "sometool.exe" sitting right next to the batch file no matter where it's run from.

setlocal
"%~dp0sometool.exe" > temp.txt
set /p TOOLOUTPUT= < temp.txt
del temp.txt
..do something with %TOOLOUTPUT%...
endlocal

29 Comments

  • You can also avoid the temp file by using:



    FOR /F &quot;tokens=*&quot; %%i in ('%~dp0sometool.exe') do SET TOOLOUTPUT=%%i



    The CMD.EXE command processor is actually quite powerful, if a little unintuitive (e.g. to suppress prompting, DEL uses /Q but XCOPY uses /Y). If you write batch files, it's worth getting a cup of coffee and spending 1/2 hour in front of a command prompt with FOR /?, SET /? etc.

  • Thanks Loren, %~dp0 enables our BizTalk setup/cleanup batchfiles to be run via Nant and the great CruiseControl.

  • I don't see why Monad will remove the need for these tricks if WSH hasn't managed to do so...

  • No offense lads but both "SET /P" or the "FOR /F" monster look frigtening compared to UNIX backquotes :-)

  • Thanks a lot.................. it really help me....; )

  • Just the kind of "shortcut" i needed!
    Thanks!
    :o)

  • So I found this blog by looking for a way to have the actual command piped to a file as well as the results.
    for /F "tokens=1 delims=" %% in (users.txt) do (command "%%S") >> outputfile.txt

    I would like the actual command piped as well, in this case the users name.

    Any ideas?

  • for /f "tokens=1 delims=" %%s in (users.txt) do (echo %%S & command "%%S") >> outputfile.txt

  • THANKS A LOT !!! I was digging into google looking for such a basic script !!!!
    batch is _really_ not bash ;-)

  • So if set/p captures a line of standard input, then I would expect this to work, but it doesn't seem to:

    dir | set /p outputfromdir=

    Any ideas why?

  • Batch File output Redirection:

    I want to redirect the output of my batch file to a .txt/.doc/.xls file.

    For that I am using the syntax:

    “C:\ProjFolder\Application.exe > Logfile.txt” and saved it as a batch file.

    My Log file is supposed to hold several 1000 lines of data.

    But my problem is that after certain limit, no data is going into the Logfile.

    Somebody please tell me the reason???

  • I'd like to capture the current time more accurately than time/t allows. Set prompt=$T gives the time in 24 hour to hundredths of a second and is just what I want.

  • @andres that's for bash, not batch (ie. linux, not windows)

    But you're right, it's waaaay easier - hence why my build scripts are a mix of bash files (cygwin) and batch files (windows)

  • This helped me. I am using this in Automated setup scripts for Sahrepoint using PSCONFIG and STSADM. I have lot of files in different directories which were needed to be installed by this script. I have to run this script from the lcation where it was stored.

    This post helped me in getting location independence and included this script in Windows directory so call it from anywhere this is what is use

    pushd .
    cd %~dp0
    ..... automated script for sharepoint installation.....
    popd

    Thanks and Regards,
    Sameer Dhoot.

  • Hi,

    I need to work with legacy batch files, and I am trying to figure out an easy way to check if a task is currently running. I am planning to put the batch job in scheduler and only run a task if it's not running.

  • Alexei,

    What version of Windows are you running?

    If it's XP, you can get a list of processes with tasklist. It may work with Vista, too, but I don't think in 2k.

    I'd use GNU sed to grab the process/line you want. It doesn't seem to glue very well to tasklist if you try to pipe the output straight into sed, but you can send the process list to a file first, then sed will do fine.

    If you have Powershell aka ps (aka Monad aka msh), you can use get-process.

  • The parms do not work for Telnet
    Does anyone know why?
    Telent does not output anything to Temp.TXT

    setlocal
    Telnet.exe xxx 443 > temp.txt
    set /p TOOLOUTPUT= < temp.txt
    del temp.txt
    ..do something with %TOOLOUTPUT%...
    endlocal

  • Thanks for the blog, it was promising, and almost worked for me, but....

    This line:

    set /p TOOLOUTPUT= < temp.txt

    only seems to accept a certain number of characters from temp.txt -- after that maximum is reached, the string inside temp.txt gets cut off.

    The workaround I found was to build temp.txt right into a batch script i.e. temp.txt for me contained 500 arguments to a program, so temp.bat called that program with the arguments.

  • I am interested to learn batch programing..

  • Nice code.
    This is what exactly i am looking for.
    Thanks a lot

  • nice aswel is timestamp environment var to spool to a timestamped batch file

    :: sets the timestamp arguments to the actual date & time

    for /f "tokens=1,2 delims=: " %%i in ('time /t') do set hhmi=%%i%%j
    for /f "tokens=2,3,4 delims=/- " %%i in ('date /t') do set yyyymmdd=%%k%%j%%i

    set log_backup_changes=%yyyymmdd%-%hhmi%_backup.log

    rman target / @%script_backup_changes% log=%log_backup_changes% append

  • Date and Time: Instead of date /t and time /t, there're the built-in %date% and %time% env vars.

    eg:

    echo %time%

    set timestamp=%date% %time%

  • Also of note: %~d0 will give the Drive Letter where the script is located.

    This would be necessary in some cases; for example, if you are running the script from a different drive, you can't simply "cd %~dp0" because you have to switch drives first.

    So you could do this in the batch file:
    %~d0
    cd %~dp0

  • Or you could simply do:

    cd /d %~dp0

    And it would change both the drive and the current dir.

  • Hello there.
    I have something to say, about AloeVera, something about which you wrote above, about health and minerals... For a long time, I and my nice friend use the products of the flp. We every time see the good results and also we make money for our families and we are happy. My friend works with Aloe Vera in the company of forever living products has more than 5 years (My friend works ONLY in the flp company and has a wife and three children). I know aloe Vera products for weight loss for a long time, but a year ago, began working as a distributor in the Forever Living Company.
    Of course, this job is some difficult, but in no other case, You can earn so much money with so much much fun and good smiling faces around..
    So if you want to discuss something about which you wrote above, and about my experience with Aloe vera products for weight loss, I'll always be glad to talk.

    Best regards from Washington state and have a nice day!
    Andrew - Aloe Vera Distributor

  • I'm surprised about all the hacks i saw in the comments to avoid the temp.txt file (such as using the for command). Why not just pipe directly from one into the other, i.e.

    sometool.exe | set /p TOOLOUTPUT=

    and thats it.

  • I may be a tad old fashioned, but I still think batch files have a place. They are lean, reasonably fast, and run without a bunch of extra infrastructure that may be missing or disabled for security reasons. For instance, WSH may be disabled, and neither Perl nor PowerShell is part of a default installation of Windows.

    Paraphrasing a comment that I heard, in a TechEd session long ago, about Notepad, CMD.EXE is everywhere.

    Apart from the one spam message that crept into it, this blog is fabulous. I found it in the course of a Google search, pinned it into my Favorites, and have referred to it several times in the last week or so.


  • Nice dialog going on here.

    Someone mentioned pipes. I use biterscripting ( http://www.biterscripting.com ) for implementing pipes.

    A pipe is a data connection between two commands. There can be four types of pipes. I will show an example of how I do this.


    THE STRAIGHT PIPE
    Output of one command goes into input of another command.
    # Code
    lf > $s
    len $s
    # End code



    THE TEE (T) PIPE
    Output of one command goes into input of two commands.
    # Code
    lf > $s
    len $s
    echo $s
    # End code



    THE WYE (Y) PIPE
    Output of two commands go into input of one command.
    # Code
    cat x.txt > $s
    cat y.txt >> $s
    echo $s
    # End code



    THE EH (H) PPE
    Output of two commands go into input of two commands.
    # Code
    cat x.txt > $s
    cat y.txt >> $s
    len $s
    echo $s
    # End code



    These four types of pipes are also called one-to-one, one-to-many, many-to-one and many-to-many. By using variables, I can implement all four. Pretty clever. But you need a language that allows you to redirect a command's output (and errors) to a variable.

  • Is there a way to block symbols being entered in a "set /p variable=" command?...

    for example:

    set /p variable=""
    echo.%variable% | findstr /R /C:[Symbol - Symbol] > nul
    IF NOT ERRORLEVEL 1 GOTO WRONG!!!

Comments have been disabled for this content.