Loren Halvorson's Blog

If your only tool is a hammer...

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

Comments

Joe said:

You can also avoid the temp file by using:

FOR /F "tokens=*" %%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.
# March 24, 2006 3:39 PM

BambooWave said:

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

# August 9, 2006 7:59 AM

Dennis said:

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

# October 22, 2006 4:38 AM

Anil said:

Great!

It really helped me!

# April 27, 2007 5:15 AM

Stl said:

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

# June 11, 2007 12:49 PM

suryakant said:

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

# June 13, 2007 5:37 AM

Shortcut said:

Just the kind of "shortcut" i needed!

Thanks!

:o)

# July 23, 2007 4:30 AM

Andamo said:

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?

# August 16, 2007 11:21 AM

Timbo said:

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

# September 24, 2007 9:57 PM

prx64 said:

THANKS A LOT !!! I was digging into google looking for such a basic script  !!!!

batch is _really_ not bash ;-)

# November 20, 2007 7:32 AM

Yako said:

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?

# March 11, 2008 11:47 AM

Arun said:

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

# April 4, 2008 7:51 AM

markc said:

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.

# June 1, 2008 8:52 PM

sascha said:

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

# June 5, 2008 8:40 PM

Sameer Dhoot said:

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.

# August 11, 2008 2:16 PM

Alexei said:

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.

# August 12, 2008 2:38 PM

Hedles said:

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.

# August 19, 2008 4:05 PM

Ken said:

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

# September 9, 2008 12:17 AM

Tai said:

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.

# December 15, 2008 1:40 AM

sachin said:

I am interested to learn batch programing..

# December 26, 2008 3:52 AM

subha said:

Nice code.

This is what exactly i  am looking for.

Thanks  a lot

# February 9, 2009 4:24 AM

Timestamp said:

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

# March 3, 2009 9:14 AM

ChernoJ said:

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%

# March 13, 2009 3:01 AM

Eric said:

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

# August 28, 2009 10:51 PM

Taz said:

Or you could simply do:

cd /d %~dp0

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

# September 8, 2009 12:58 PM

Aloe Vera Distributor - myflp.org said:

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

# September 29, 2009 3:10 PM

Grant Peters said:

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.

# October 7, 2009 1:21 AM

David Gray said:

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.

# October 28, 2009 6:58 PM

Sen2008 said:

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.

# December 3, 2009 4:27 PM

Sham69 said:

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

# December 12, 2009 3:40 PM