java shell

From Noah.org
Jump to navigationJump to search


This shows how to call an external script from Java. This is intended for UNIX systems, but may work under other systems if you substitute a different shell or if you install CYGWIN.

import java.io.*;
import java.util.*;

public class shell
{

    /** This tests the runBashShellCommand method.
     *  The following are some examples of how it works:
     *
     *      $ java shell echo Hello
     *      0
     *      Hello
     *
     *      $ java shell "echo Hello; exit 1"
     *      1
     *      Hello
     *
     *      $ java shell "echo Hello; exit 0"
     *      0
     *      Hello
     */

    public static void main(String args[])
        throws IOException, java.lang.InterruptedException
    {
        System.out.println (runBashShellCommand (args));
    }

    /** This runs a command in a Bash shell and returns the output.
     *
     * For example, the following should print "hello":
     *
     *      String [] args = {"foo=hello", ";", "echo", "$foo"};
     *      System.out.println (runBashShellCommand (args));
     *
     * You may combine commands and arguments into a single string.
     * This is equivalent to the previous example:
     *
     *      String [] args = {"foo=hello ; echo $foo"};
     *      System.out.println (runBashShellCommand (args));
     *
     * This method will CLOSE the stdin of the subprocess so that it cannot
     * read from this filedescriptor. For example, the following should be
     * safe; Bash will simply set 'foo' to an empty string instead of blocking
     * on the 'read' call.
     *
     *      String [] args = {"read", "foo", ";", "echo", "$foo"};
     *      System.out.println (runBashShellCommand (args));
     *
     * Comments: This method is probably overkill.
     *
     * @author Noah Spurrier
     * @param args The first element should be the command to be run.
     *               Additional elements should be arguments.
     * @return the output of the command as a String. The first line of the
     *          string will be the exit code from the command that was run.
     * @throws IOException if there was a problem with the subshell.
     * @throws InterruptedException if the subshell was killed.
     */

    public static String runBashShellCommand (String args[])
        throws IOException, java.lang.InterruptedException
    {
        java.util.List<String>
            command_and_args = new java.util.ArrayList<String> ();
        command_and_args.add ("/bin/bash");
        command_and_args.add ("-c");
        StringBuffer cmd_string = new StringBuffer ();
        for (String arg : args) { cmd_string.append (arg).append (' '); }
        command_and_args.add (cmd_string.toString().trim());

        // Start Bash and script.
        ProcessBuilder pb = new ProcessBuilder (command_and_args);
        pb.redirectErrorStream (true);
        Process process = pb.start ();

        //////////////////////////////////////////////////////////////////////
        // WARNING: There is a race condition here. We want the subprocess to
        // have its stdin cutoff BEFORE it actually tries to read from stdin.
        // This is mainly to be proper; not to prevent any sort of dead-lock.
        // There is no danger that this will block us since the subprocess runs
        // asynchronously. This shouldn't be a big deal, but it should be
        // tested to be sure. -- Noah
        process.getOutputStream().close();

        // Get output from the command.
        BufferedReader br = new BufferedReader (new
                InputStreamReader (process.getInputStream()));
        StringBuffer out = new StringBuffer ();
        String line = null;
        while ((line = br.readLine ()) != null)
        {
            out.append (line).append ('\n');
        }
        // Wait for process to finish.
        int exit_code = process.waitFor();
        out.insert (0, String.valueOf(exit_code) + "\n");
        return out.toString();
    }
}