Java Runtime.exec() to run a java program - java

Here's the situation. Im creating a UI which will allow make using a genetic programming system (ECJ) easier to use.
Currently you need to run a command prompt within the ECJ folder and use the commands similar to this to execute a parameter file.
java ec.Evolve -file ec\app\tutorial5\tutorial5.params
Where the full path of tutorial5 is
C:\Users\Eric\Documents\COSC\ecj\ec\app\tutorial5\tutorial5.params
and the command prompt must be executed from
C:\Users\Eric\Documents\COSC\ecj
My program makes the user select a .params file (which is located in a ecj subdirectory) and then use the Runtime.exec() to execute
java ec.Evolve -file ec\app\tutorial5\tutorial5.params
What i have so far
// Command to be executed
String cmd = "cd " + ecjDirectory;
String cmd2 = "java ec.Evolve -file " + executeDirectory;
System.out.println(cmd);
try {
Process p = Runtime.getRuntime().exec(
new String[]{"cmd.exe", "/c", cmd, cmd2});
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
statusTF.append(r.readLine());
p.waitFor();
} catch (IOException | InterruptedException ex) {
System.out.println("FAILED: " + ex.getMessage());
statusTF.append("Failed\n");
}
Currently it outputs the change directory command but nothing else.
Can this be done?

First, the 'cd' command can't be executed by Runtime.exec() in the first place (see How to use "cd" command using Java runtime?). You should be able to just set the working directory for the process when you call exec (see below).
Second, running 'cmd.exe /c' to execute your process isn't what you want here. You won't be able to get the results of your process running, because that is returned to the command window -- which eats the error and then closes without passing the error along to you.
Your exec command should look more like this:
Process p = Runtime.getRuntime().exec(
command, null, "C:\Users\Eric\Documents\COSC\ecj");
Where 'command' looks like this:
String command = "java ec.Evolve -file ec\app\tutorial5\tutorial5.params"
Edit: For reading error messages, try this:
String error = "";
try (InputStream is = proc.getErrorStream()) {
error = IOUtils.toString(is, "UTF-8");
}
int exit = proc.waitFor();
if (exit != 0) {
System.out.println(error);
} else {
System.out.println("Success!");
}

You can use Java processbuilder:
processBuilder documentation!
you can define the working directory of the process and all other stuff.

Each call to exec() runs in a new environment, this means that the call to cd will work, but will not exist to the next call to exec().
I prefer to use Apache's Commons Exec, it's provides an excellent facade over Java's Runtime.exec() and gives a nice way to specify the working directory. Another very nice thing is they provide utilities to capture standard out and standard err. These can be difficult to properly capture yourself.
Here's a template I use. Note that this sample expects an exit code of 0, your application may be different.
String sJavaPath = "full\path\to\java\executable";
String sTutorialPath = "C:\Users\Eric\Documents\COSC\ecj\ec\app\tutorial5\tutorial5.params";
String sWorkingDir = "C:\Users\Eric\Documents\COSC\ecj";
try (
OutputStream out = new ByteArrayOutputStream();
OutputStream err = new ByteArrayOutputStream();
)
{
// setup watchdog and stream handler
ExecuteWatchdog watchdog = new ExecuteWatchdog(Config.TEN_SECONDS);
PumpStreamHandler streamHandler = new PumpStreamHandler(out, err);
// build the command line
CommandLine cmdLine = new CommandLine(sJavaPath);
cmdLine.addArgument("ec.Evolve");
cmdLine.addArgument("-file");
cmdLine.addArgument(sTutorialPath);
// create the executor and setup the working directory
Executor exec = new DefaultExecutor();
exec.setExitValue(0); // tells Executor we expect a 0 for success
exec.setWatchdog(watchdog);
exec.setStreamHandler(streamHandler);
exec.setWorkingDirectory(sWorkingDir);
// run it
int iExitValue = exec.execute(cmdLine);
String sOutput = out.toString();
String sErrOutput = err.toString();
if (iExitValue == 0)
{
// successful execution
}
else
{
// exit code was not 0
// report the unexpected results...
}
}
catch (IOException ex)
{
// report the exception...
}

Related

how can I execute "java" command by java code?

I'm trying to run a multi-agent system using JADE by code.
Usually, I can run the jade system by command line using the following command:
java jade.Boot -gui
It also works well using Netbeans IDE by changing the project properties and pointing the run configuration to the jade.Boot class.
My problem is: I want to run this system by java code... let's say, when a user clicks a button, and as far as I know, this command specified above should work using the following code:
Process p=null;
try {
p = Runtime.getRuntime().exec("java jade.Boot -gui;");
}
catch (IOException ex) {
Logger.getLogger(SimulationCreator.class.getName()).log(Level.SEVERE, null, ex);
}
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
String s;
try {
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
} catch (IOException ex) {
Logger.getLogger(SimulationCreator.class.getName()).log(Level.SEVERE, null, ex);
}
But I'm getting nothing, neither the JADE system is running nor I'm getting any error.
What am I missing ?
P.S.: I'm working on ubuntu 20.0.
P.S.: running other commands by code like "ps -aux" works very well!
Your problem may be a difference between PATH of the current running VM, compared the shell (bash etc) you use and implicit passing of CLASSPATH. Check the location of java which which java in the shell that works and try using in your exec.
Also you won't see all issues when running as you don't access the error stream at same time as the output stream, changing to ProcessBuilder allows easier debugging as you can redirect the out/err streams to a file. But if JADE runs for a long time or produces a lot of output you should consumer STDOUT+ERR in background threads.
Try this in jshell:
String[] cmd = new String[]{"java", "jade.Boot", "-gui"};
ProcessBuilder pb = new ProcessBuilder(cmd);
File fileOut = new File("stdout.log");
File fileErr = new File("stderr.log");
pb.redirectError(fileErr);
pb.redirectOutput(fileOut);
Process p = pb.start();
int rc = p.waitFor();
String stdout = Files.readString(fileOut.toPath());
String stderr = Files.readString(fileErr.toPath());
System.out.println("Exit : "+rc +' '+(rc == 0 ? "OK":"**** ERROR ****"));
System.out.println("STDOUT : "+stdout);
System.out.println("STDERR : "+stderr);

How do I run GDB and accept GDB commands through Java output console?

I am trying to build a GUI for GCC which has some basic functionalities like compile, link, execute, debug, etc for C++ programs using Java. I am creating strings of command which I pass to the ProcessBuilder and run it via command prompt and GCC.
command = "cd src & cd Resources & g++ " + compileFile.cpp +" -Wall "+ " -o "+ "tempOut";
This is a sample code for compiling the file.
Part of this is the debug functionality for which I am using GDB. Now the problem is GDB needs additional input to add breakpoints, remove breakpoints and so on. I am having trouble on how to pass these necessary inputs to GDB via Java terminal. If I pass the commands in the command prompt, it is working fine and I get the desired output.
enter image description here
But whenever I fire the GDB command from the Java program, I cannot pass any inputs from the IDE's terminal. I am aware that each GDB command uses a different process and I tried attaching Java's process ID to GDB but I just get a blank output console. It seems that the GDB session has started but there is no way to interact with that process through the IDE's output console.
int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("#")[0]);
command = "gdb attach "+ pid;
fireCommand();
EDIT
This is the method that interacts with command prompt to take input and display output in the IDE's output console:
public void fireCommand() {
String line;
String os = System.getProperty("os.name");
ProcessBuilder builder;
if(os.startsWith("Win")) {
builder = new ProcessBuilder("cmd.exe", "/c", command);
}
else{
builder = new ProcessBuilder("bash", "-c", command);
}
try {
process = builder.start();
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
while ((line = reader.readLine()) != null) {
if(line.contains("Input the value")) {
//any other user input in non debug execution
String value = JOptionPane.showInputDialog(line);
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(process.getOutputStream()));
writer.write(value, 0, value.length());
writer.newLine();
writer.close();
}
else {
output.append(line).append("\n");
}
}
int exitVal = process.waitFor();
if (exitVal == 0) {
//display("Success!");
display(output.toString());
} else {
String lineErr;
BufferedReader readerErr = new BufferedReader(
new InputStreamReader(process.getErrorStream()));
while ((lineErr = readerErr.readLine()) != null) {
outputErr.append(lineErr).append("\n");
}
//display(exitVal);
display(outputErr.toString()); //Display the uncatched errors
}
} catch (IOException e) {
display("There was a problem with the I/O");
e.printStackTrace();
} catch (InterruptedException e) {
display("There was a interruption with the execution");
e.printStackTrace();
}
if(!outputErr.toString().isEmpty())
errorFormatDisplay(); //display Error output function
}
Any leads on this would be very helpful. Thank you.
I am aware that each GDB command uses a different process
No, gdb runs as one process. Did you mean to say that you are creating a new gdb process every time you try to pass it a gdb command ?
It seems that the GDB session has started but there is no way to interact with that process through the IDE's output console.
Maybe you should use The GDB/MI Interface, which e.g. the Emacs debugger mode gud uses.

java.lang.Runtime exception "Cannot run program"

I am getting an exception like java.io.IOException: Cannot run program cat /home/talha/* | grep -c TEXT_TO_SEARCH": error=2, No such file or directory while executing the command below despite that there are no issues when I execute the same command through the terminal. I need to execute and return the output of the command below:
cat /home/talha/* | grep -c TEXT_TO_SEARCH
Here is the method used to execute commands using Runtime class:
public static String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
Runtime.exec does not use a shell (like, say, /bin/bash); it passes the command directly to the operating system. This means wildcards like * and pipes (|) will not be understood, since cat (like all Unix commands) does not do any parsing of those characters. You need to use something like
p = new ProcessBuilder("bash", "-c", command).start();
or, if for some bizarre reason you need to stick to using the obsolete Runtime.exec methods:
p = Runtime.getRuntime().exec(new String[] { "bash", "-c", command });
If you are only running that cat/grep command, you should consider abandoning the use of an external process, since Java code can easily traverse a directory, read lines from each file, and match them against a regular expression:
Pattern pattern = Pattern.compile("TEXT_TO_SEARCH");
Charset charset = Charset.defaultCharset();
long count = 0;
try (DirectoryStream<Path> dir =
Files.newDirectoryStream(Paths.get("/home/talha"))) {
for (Path file : dir) {
count += Files.lines(file, charset).filter(pattern.asPredicate()).count();
}
}
Update: To recursively read all files in a tree, use Files.walk:
try (Stream<Path> tree =
Files.walk(Paths.get("/home/talha")).filter(Files::isReadable)) {
Iterator<Path> i = tree.iterator();
while (i.hasNext()) {
Path file = i.next();
try (Stream<String> lines = Files.lines(file, charset)) {
count += lines.filter(pattern.asPredicate()).count();
}
};
}
$PATH is an environment variable that tells the system where to search for executable programs (it's a list of directories separated by colons). It is usually set in your .bashrc or .cshrc file but this is only loaded when you log in. When Java runs, $PATH is likely not set because the rc file is not executed automatically, so the system can't find programs without specifying exactly where they are. Try using /bin/cat or /usr/bin/cat instead of just cat and see if it works. If it does, $PATH is your problem. You can add $PATH=/bin:/usr/bin to your script or just leave it with the directory name specified (e.g. /bin/cat).
Just because you can execute it in a login session doesn't mean it will work the same when a daemon like your Java program runs. You have to know what's in your .bashrc or .cshrc file and even sometimes how the system file is written (/etc/bashrc) in order to know how to write a script that runs under a daemon. Another consideration is that daemons often run under the context of a different user, and that throws things off, too.

Execute commands in CMD on Windows with Java code

I want to write a Java code that would perform commands in Windows CMD.
I looked through the site and found out how to send and work with single request. For example create new Process and in execute ("cmd /c dir") then using input stream I can get the answer that is displayed.
How to open the process of cmd and let the user to enter cmd commands?
For example, I open application and it directly opens cmd process, then user can type "dir" and get the output.
After type "cd ../../"
and after type "dir" again and get the output with new path containment.
If it can be performed then how to do it? Or in order to perform this need to open each time a new process and execute ("cmd /c some_reqests")?
Nice question, you can in fact call cmd as a new process and use standard input and standard output to process data.
The tricky part is knowing when the stream from a command has ended.
To do so I used a string echoed right after the command (dir && echo _end_).
In practice I think it would be better to simply start a process for each task.
public class RunCMD {
public static void main(String[] args) {
try {
Process exec = Runtime.getRuntime().exec("cmd");
OutputStream outputStream = exec.getOutputStream();
InputStream inputStream = exec.getInputStream();
PrintStream printStream = new PrintStream(outputStream);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
printStream.println("chcp 65001");
printStream.flush();
printStream.println("dir && echo _end_");
printStream.flush();
for(String line=reader.readLine();line!=null;line=reader.readLine()){
System.out.println(line);
if(line.equals("_end_")){
break;
}
}
printStream.println("exit");
printStream.flush();
for(String line=reader.readLine();line!=null;line=reader.readLine()){
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
try this
Process p = Runtime.getRuntime().exec("ps -ef");
found it at http://alvinalexander.com/java/edu/pj/pj010016

Java program that calls external program behaving asynchronously?

All,
I originally had a shell script that called SQLLoader (Oracles data upload tool).
The problem was that SQLLoader takes a plain text password as input so I decided to build a Java application to call SQLLoader internally passing a decrypted password into the command string.
e.g.
sqlldr user/pass#DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv
So with my java wrapper it became this in my shell script
java -jar sqlloader.jar sqlloader.ctl mydata.csv
However a new problem developed when SQLLoader complained there was no file to load. After some head scratching it was discovered that a subsequent command in my shell script seemed to be executing while my java application was still running. Therefore it was behaving asynchronously.
The next command was moving the input file sqlloader was using before it could get a chance to use it. So I put a sleep command in of 20 seconds to give my java application time to run.
java -jar sqlloader.jar sqlloader.ctl mydata.csv
echo $?
sleep 20
if [ $? -ne 0 ]
then
echo "SQLLoader failed during execution, please check the log : "
mv mydata.csv
else
echo "SQLLoader successfully processed file : "
mv mydata.csv
fi
Does anyone know why unix is behaving this way, does Java execute my SQLLoader as a different user/ thread?
This is my java code:
Runtime Rt;
Process Prc;
Prc = Rt.exec("sqlldr user/decryptedpass#DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv);
system.exit(0);
I checked the Runtime Class for anything about it being Asynchronous but couldnt find anything
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html
Any theories or suggestions?
Thanks
Yes. If you look at Runtime.exec again it does specify that it will launch a new process in the specified environment (e.g. independently of the current "environment" or as you put it asynchronously). You should use ProcessBuilder to create a Process and then waitFor that Process to finish before calling System.exit - which certainly isn't mandatory. Something like this
public static void main(String[] args) {
// String command = "/usr/bin/sleep 5";
List<String> command = new ArrayList<String>();
command.add("c:/cygwin/bin/sleep");
command.add("5");
ProcessBuilder pb = new ProcessBuilder(command);
BufferedReader is = null;
try {
System.out.println("Starting command " + command);
Process p = pb.start();
int ret = p.waitFor();
is = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = is.readLine()) != null) {
System.out.println(line);
}
if (ret == 0) {
System.out.println("Command has completed.");
System.exit(ret);
} else {
System.out.println("Command completed with return code " + ret);
System.exit(ret);
}
} catch (Exception e) {
System.out.println("Caught Exception " + e.getMessage()
+ " running command " + command);
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
System.out.println("COMMAND FAILED");
System.exit(1);
}
You need to wait for process completion, you should also read all output (stdout and stderr) from the process you are starting.
If you call exit() after exec(), Java will do just that - exit immediatedly.
Here is an article that explains Runtime.exec pitfalls: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 (also consider the other pages).

Categories