user63898
user63898

Reputation: 30915

Executing linux mutt from Java Runtime.getRuntime not sending mail and not giving error

I try to send email using mutt in linux and java if I execute the mutt command from linux command line the email send great

echo "test" | mutt -s "subject" -- "[email protected]

now I have this simple java app that I try to execute the same command and I get nothing, not even error:

java -cp runtime-SNAPSHOT.jar MyApp "echo \"test\" | mutt -s \"subject\"  \"[email protected]\""

class StreamGobbler extends Thread
{
    InputStream is;
    String type;

    StreamGobbler(InputStream is, String type)
    {
        this.is = is;
        this.type = type;
    }

    public void run()
    {
        try
        {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            while ( (line = br.readLine()) != null)
                System.out.println(type + ">" + line);
        } catch (IOException ioe)
        {
            ioe.printStackTrace();
        }
    }
}
public class MyApp {

    public static void main(String[] args) throws InterruptedException, IOException {

        if (args.length < 1)
        {
            System.out.println("USAGE: java GoodWindowsExec <cmd>");
            System.exit(1);
        }
        try
        {
            String[] cmd = new String[3];
            Runtime rt = Runtime.getRuntime();
            System.out.println("Execing " + args[0] );
            Process proc = rt.exec(args[0]);
            // any error message?
            StreamGobbler errorGobbler = new
            StreamGobbler(proc.getErrorStream(), "ERROR");
            // any output?
            StreamGobbler outputGobbler = new
            StreamGobbler(proc.getInputStream(), "OUTPUT");
            // kick them off
            errorGobbler.start();
            outputGobbler.start();
            // any error???
            int exitVal = proc.waitFor();
            System.out.println("ExitValue: " + exitVal);
        } catch (Throwable t)
        {
            t.printStackTrace();
        }
}

what is wrong here?

Upvotes: 1

Views: 414

Answers (1)

kai
kai

Reputation: 905

You get no error as echo seems to be available on your system(usually as "/bin/echo") . The Stringtokenizer in the Runtime exec method passes the rest of your line as parameters to /bin/echo like this:

/bin/echo "\"test\"" "|" "mutt" "-s" "\"subject\"" "--" "\"[email protected]\""

Well this is a valid comand as it calls /bin/echo and /bin/echo outputs all the parameters but never calls mutt. (btw. /bin/echo is a different echo than the one used in a Bash shell which is a builtin and behaves a little different...)

That they(Java) tokenize the command in the exec method may be convenient sometimes but leads to quite irritating effects like this because it makes one assume that something should work, that actually doesn't as in this case...

What you probably want is a shell executing your command line. So you have to actually execute a shell(I marked the change in the file):

public class MyApp {

    static class StreamGobbler extends Thread {

        InputStream is;
        String type;

        StreamGobbler(InputStream is, String type) {
            this.is = is;
            this.type = type;
        }

        public void run() {
            try {
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String line = null;
                while ((line = br.readLine()) != null) {
                    System.out.println(type + ">" + line);
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException, IOException {

        /*if (args.length < 1) {
            System.out.println("USAGE: java GoodWindowsExec <cmd>");
            System.exit(1);
        }*/
        args = new String[]{"echo \"test\" | grep -i \"s\" " };
        try {
            String[] cmd = new String[3];
            Runtime rt = Runtime.getRuntime();
            System.out.println("Execing " + args[0]);
            //Change here: execute a shell with the command line instead of echo:
            Process proc = rt.exec(new String[]{"/bin/sh","-c", args[0]});
            // any error message?
            StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");
            // any output?
            StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT");
            // kick them off
            errorGobbler.start();
            outputGobbler.start();
            // any error???
            int exitVal = proc.waitFor();
            System.out.println("ExitValue: " + exitVal);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

}

Sidenote. For a better minimal testcase:

  • I replaced your mutt command with some grep as I don't wan't to send mails ;)
  • I faked the java command line by creating the array("args") programatically.

  • made your StreamGobbler static in order to have it one file.

All that shouldn't change your testcase. What does make a difference is the rt.exec call that executes a shell instead of /bin/echo

example run:

Execing echo "test" | grep -i "s" 
ExitValue: 0
OUTPUT>test

Upvotes: 2

Related Questions