Executing System Commands with ColdFusion


Update 19 March 2010: Note that as of ColdFusion 8 onwards cfexecute allows you to capturing the standard and error outputs.


Update 13 May 2008: This project has been moved over to RIA Forge at http://systemcommand.riaforge.org/

This is an update to a previous entry.

Typically when you want to execute a system command you would use the <cfexecute> tag, but there are some situations when this may not be ideal such as when you want to capture both the “standard output” and “error output” streams of the system command.

Standard Output Stream and Error Output Stream

Many command line programs send output to two data ‘streams’:

a) Standard output stream

b) Error output stream

When you manually execute a program the command line information sent to either stream is simply displayed on the screen – there is no distinction which stream is being used.

Example

For example, suppose we execute the command to determine the version of java running on your system. You may execute the following command:

java -version

Which on my machine results in:

java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode)

The problem with <cfexecute>

Suppose you execute the command above using using:

<cfexecute name="java" arguments="-version" timeout="1" variable="output" />
<cfoutput>#output#</cfoutput>

This produces no output!

What happened? Well, cfexecute can only capture output sent to the standard output stream, but not anything sent to the error output stream.

In this example, the java -version command sends all of its output to the error output stream (which seems a bit odd, but it came in useful for this example).

So how can we capture both the standard output and the error output streams?

Using a batch file wrapper

One method of capturing both streams is to put the command inside a batch file and send the two output streams to two files, then read them back in again:

Suppose we have a file javaversion.bat with the content

java -version

Then we run the batch file (on a windows machine) as follows

javaversion.bat 1>stdout.txt 2>errout.txt

This is just the syntax for capturing the standard output (stream 1) and error output (stream 2)

This will result in the creation of two files:

stdout.txt which has no data.

errout.txt which has the version data.

The next step would be to read in the files just created to get the output data.

Using Java

The previous entry on executing system commands described a technique of using inline Java code within ColdFusion, but this technique does not work for all executables.

The problem is that the standard output and error output streams need to be read simultaneously rather than sequentially. We can use a small Java application to help us in achieving this.

Installation

1. Download SystemCommand Component. This contains the Java source code and a systemcommand.jar file.

2. Add the systemcommand.jar file to your "Java class path".

This is done by either

a) Copying the systemcommand.jar file to your C:ColdFusion8lib directory (or the equivalent lib directory for your version of ColdFusion).

or

b) Adding the systemcommand.jar file to your Java class path within the ColdFusion administrator,

3. Restart the ColdFusion service so the new .jar file is picked up.

Usage

Once the systemcommand.jar file has been successfully installed, it can be used from within ColdFusion.

The system command object is created using the command:

<cfset syscmd = createObject("java","au.com.webcode.util.SystemCommand").init()>

This object has one function: execute(command,timeout).

<cfset result = syscmd.execute(command,timeout)>

The parameters are:

command The full command string to execute.
timeout (Optional) A timeout in milliseconds. The process will be terminated when the timeout is reached and an Exception will be thrown. The default timeout is 10 seconds.

Return Value

The value returned from the execute() function is an object with the following functions:

getCommand() The original command that was executed.
getStandardOutput() The standard output produced by the command.
getErrorOutput() The error output produced by the command.
getExitValue() An integer value provided by the process that was executed. A value of zero usually indicates that all was fine. A non zero value usually indicates a problem occurred.

Example

A simple example of ColdFusion code to use the system command utility.

<cfset command = "java -version">
<cfset syscmd = createObject("java","au.com.webcode.util.SystemCommand").init()>
<cfset result = syscmd.execute(command)>
<cfoutput>
	Command: #result.getCommand()#<br>
	ExitValue: #result.getExitValue()#<br>
	Error Output: #result.getErrorOutput()#<br>
	Standard Output: #result.getStandardOutput()#<br>
</cfoutput>

Download

Download SystemCommand Component.

Good luck!

This entry was posted in ColdFusion and tagged . Bookmark the permalink. Both comments and trackbacks are currently closed.

16 Comments

  1. Danilo Celic
    Posted March 26, 2008 at 7:09 am | Permalink

    Thanks for the tidbit about the Java version outputting to the error output stream. I recently ran into not being able to redirect the output for "java -version" to a file and now I know why that is the case, it wasn’t "regular" output it was error output. I searched for quite a while and never ran into a reference that stated that it outputs to the error stream. I ended up writing a simple class file that output the Java version, and I then was able to redirect its output to the file I wanted it to, but I may switch back now that you mention this.

    How did you find out that it outputs to the error stream? Did you just stumble upon it by trying to redirect to the error stream (which for some reason I never even thought to try it, or if I did I did it wrong some how), or did you know this from some other reference? If the later, do you have a link?

  2. Posted March 26, 2008 at 11:54 am | Permalink

    Hi Danilo

    Finding out that java -version goes to the error stream was unexpected. I was testing the previous version of this code (http://stannard.net.au/blog/index.cfm/2007/9/21/executing-system-commands-with-coldfusion) on various commands and discovered this by accident.

  3. Sami Hoda
    Posted March 26, 2008 at 2:34 pm | Permalink

    This is great! Will have to switch over from the CFC to the JAR now.

  4. Gabriel
    Posted March 26, 2008 at 2:38 pm | Permalink

    Just wanted to thank you for the post. It was one of those "hey, that’s _exactly_ what I need" moments as I saw it in the RSS aggregator. So, thank you.

  5. Danilo Celic
    Posted March 26, 2008 at 3:35 pm | Permalink

    Kevan,

    Thanks for the feedback on how you came across where Java outputs its version number.

    I might just be able to use the JAR for other purposes, so thanks for the effort.

  6. Posted March 27, 2008 at 4:27 am | Permalink

    Sami, nice to hear the CFC is still kicking along for you. Let me know if you have any issues with the new version.

    Gabriel, Danilo, you’re welcome!

  7. Russ Schmidt
    Posted May 6, 2008 at 4:03 pm | Permalink

    You should post this to http://www.riaforge.org!

    BTW I am an internal Adobe developer – NOT on the ColdFusion team – and this is strictly my own opinion.

  8. Posted May 7, 2008 at 5:15 am | Permalink

    Russ, thanks for the suggestion – I will look into it.

  9. Posted May 31, 2008 at 7:35 pm | Permalink

    Anyone know if this works on *nix, Solaris etc?

  10. Posted June 2, 2008 at 4:50 am | Permalink

    Hi Mark

    Not sure. I have posted your question on riaforge as well:

    http://systemcommand.riaforge.org

  11. Chris
    Posted December 19, 2008 at 8:37 am | Permalink

    Is it possible to specify a timeout 0 (non-blocking mode) and capture the PID of the spawned process? I’d like to run a short-lived server process and briefly interacts with Coldfusion, but I need the PID so I can terminate the process at the end of the request.

  12. Posted December 19, 2008 at 1:38 pm | Permalink

    Hi Chris

    I don’t believe we can access the PID from Java without extending out into some native win32 code, but for a non-blocking solution you may be able to do something like this:

    <cfset cmd = "… your command …">
    <cfset runtime = createObject("java", "java.lang.Runtime")>
    <cfset process = runtime.getRuntime().exec(cmd)>

    You could stores the "process" variable in your session or application scope and have access to it at a later time to terminate. However getting access to the standard or error output is difficult to achieve with this approach.

  13. Chris
    Posted December 19, 2008 at 3:06 pm | Permalink

    Thanks Kevan! That’s exactly what I need.

  14. Posted March 18, 2010 at 2:19 pm | Permalink

    I have to ask – why didn’t you use errorVariable and errorFile? Unfortunately they were only documented in the 801 release notes (and missing from CF9!) but they provide support for capturing errors (either to a file or to a variable).

  15. Posted March 18, 2010 at 2:20 pm | Permalink

    I see that you wrote this back in 08. I _think_ 801 may have been out around then, but if it was not, then it certainly makes sense why you would need this workaround. :) I just worry that people will see this entry and think they can’t capture errors in cfexecute.

  16. Posted March 18, 2010 at 3:43 pm | Permalink

    Thanks Ray, I’ve added an update note.

One Trackback

  1. By Executing System Commands with ColdFusion on March 2, 2011 at 8:58 pm

    [...] This entry has been updated! [...]