0

How do I pass a string with spaces to an execute command in Java to execute a bash script?

I'm trying to use a script to generate and send a email using the unix mail command but it ignores the quotes surrounding the message string:

#!/bin/bash

######################################################
#
# Params:
# 1) Email recipient
# 2) Subject line (in quotes)
# 3) Message (in quotes)
#
# Returns:
# 0 if success, else non-zero
#####################################################

MAIL_TO=$1
SUBJECT_LINE=$2
MESSAGE=$3

echo "Mail To= ${MAIL_TO}" >> /logs/terminalLog.txt
echo "Subject= ${SUBJECT_LINE}" >> /logs/terminalLog.txt
echo "Message= ${MESSAGE}" >> /logs/terminalLog.txt
echo "" >> /logs/terminalLog.txt

echo "$MESSAGE" | mail -s "$SUBJECT_LINE" $MAIL_TO >> /logs/terminalLog.txt

and this is how I'm calling it in java :

Process proc = Runtime.getRuntime().exec(scriptName+" me@someplace.com \"My Test Subject Line\" \"This is the test message!!\"");

The problem is it takes "My as the subject argument and Test as the message argument and ignores the rest.

I have tried using single quotes, exec(command, args) where

args = {"me@someplace.com","My Test Subject Line","This is the test message!!" } 

but still has the same result.

I have searched here and online but most people seem to suggests what I have tried and while it worked for them, it did not for me.

Update

On the Advice of a number of comments/Answers I have changed from using the exec to

ProcessBuilder pb = new ProcessBuilder(scriptName, "me@somePlace.com","My Test Subject Line", "This is the test message!!");
pb.start();

I now successfull get the correct Arguments as shown by the output to log BUT I never recieve the email. If I call the script via the terminal manually I do recieve the email

jonnie
  • 12,260
  • 16
  • 54
  • 91
  • 1
    Breaking the command into a `String[]` should work, then update it to use `ProcessBuilder`. But for better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson May 13 '13 at 12:38
  • Not answering your question, but have you considered using the [JavaMail API](http://www.oracle.com/technetwork/java/javamail/index.html)? – Greg Kopff May 13 '13 at 12:43
  • @greg Kopff We have and our Tech Lead decided it required to much Permissions that we needed to get approved, this was just a work around as we only need a simple notification – jonnie May 13 '13 at 12:45
  • Try `"\"My Subject Line\""` and `"\"This is the test message!!\""`. This should send an actual quote mark to the terminal, grouping your string – David K May 13 '13 at 12:46

3 Answers3

2

This was actually solved by changing:

String command =    scriptName+" "+mailTo+" "+"\""+subject+"\""+" "+"\"" + message + "\"";
Runtime rtime = Runtime.getRuntime();
Process proc = rtime.exec(command.toString());
int retCode = proc.waitFor();           

To:

 Runtime rtime = Runtime.getRuntime();
 Process proc = rtime.exec(new String[] {this.scriptName, mailTo, subject, message} );
 int retCode = proc.waitFor();

I had also Perviously tried passing an array of strings args = {this.scriptName, mailTo, subject, message} but for some reason it did not like this

jonnie
  • 12,260
  • 16
  • 54
  • 91
1

Don't use Runtime.exec(), always use ProcessBuilder which allows you to pass arguments as an array or a collection of Strings.

And for better error handling, you should really use the Java Mail API and a logging framework like slf4j.

If you're unsure how to use ProcessBuilder and I/O between processes, you should better use Commons Exec which solves many of the common problems like handing the three I/O streams correctly.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • I have changed it to use ProcessBuilder as you and suggested, It is now successfully getting the correct arguments but, I never actually receive the mail but id I execute the script myself on the terminal I do, any suggestions? – jonnie May 13 '13 at 13:04
  • You also need to close stdin, read both stdout and stderr and call `waitFor()` to make sure the process can terminate correctly. – Aaron Digulla May 13 '13 at 13:41
  • I'm sorry but I don't fully understand, could you possibly show me an example ( even a link to one would be great) – jonnie May 13 '13 at 13:44
1

As others have mentioned, use ProcessBuilder. However, just starting the process isn't enough; you must consume its output, and you may or may not want to wait for it to complete. For example:

ProcessBuilder pb = new ProcessBuilder(scriptName, "me@somePlace.com","My Test Subject Line", "This is the test message!!");
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.start();

int returnCode = pb.waitFor();
if (returnCode != 0) {
    throw new IOException("Command failed with code " + returnCode);
}

It isn't just the process invocation that needs to quote spaces. I'm pretty sure you need quotes in your script:

SUBJECT_LINE="$2"
MESSAGE="$3"
VGR
  • 40,506
  • 4
  • 48
  • 63
  • Unfortunitly I'm using Java 6 and you seem to be using Java 7, also the quotes don't seem to cause any issue when I call the script manually, but I will try anyway – jonnie May 13 '13 at 14:29
  • I see. In that case, you'll probably want to pass `process.getInputStream()` to a new thread that continually reads and discards (or logs) bytes. – VGR May 13 '13 at 22:14