I am supposed to make an IDE for my project. Here I have to execute a java program(suppose Hello world ) via a Shell command from a specific java program. I know how to execute a shell command via java program (using Runtime.getRuntime()),but how do I invoke run a java program using this shell command.
Start with ProcessBuilder, it will allow you to separate each command argument as a separate parameter, removing the need to "quote" arguments that have spaces (like paths), it will allow you to specify the starting location of the command (working directory) and the redirection support makes it easier to extract information from the output of the command (although you might like to keep it separate)...
List<String> cmds = new ArrayList<String>(5); // You can use arrays as well
cmds.add("java");
cmds.add("-jar");
cmds.add("filename.jar");
ProcessBuilder pb = new ProcessBuilder(cmds);
pb.redirectErrorStream(true);
pb.directory(new File("...")); // Working directory...
Process p = pb.start();
// Normal processing of the Process...
You can even specify the environment variables passed to the process...
Take a look at the Java Docs for more details
This will work.
Setup the commands and then create runtime and execute command there.
String command[] = new String[4];
command[0] = "cmd";
command[1] = "/k start cmd /k";
command[2] = "java";
command[3] = path;
Process p = Runtime.getRuntime().exec(command);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); //This will allow you to supply with input
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); //This will provide you access to the errors.
pw = new PrintWriter(p.getOutputStream());
pw.println("next commands");
The PrintWriter object will allow you to execute more commands.
Related
I'm trying to use Java's ProcessBuilder class to execute a command that has a pipe in it. For example:
ls -l | grep foo
However, I get an error:
ls: |: no such file or directory
Followed by:
ls: grep: no such file or directory
Even though that command works perfectly from the command line, I can not get ProcessBuilder to execute a command that redirects its output to another.
Is there any way to accomplish this?
This should work:
ProcessBuilder b = new ProcessBuilder("/bin/sh", "-c", "ls -l| grep foo");
To execute a pipeline, you have to invoke a shell, and then run your commands inside that shell.
The simplest way is to invoke the shell with the command line as the parameter. After all, it's the shell which is interpreting "|" to mean "pipe the data between two processes".
Alternatively, you could launch each process separately, and read from the standard output of "ls -l", writing the data to the standard input of "grep" in your example.
Since Java 9, there’s genuine support for piplines in ProcessBuilder.
So you can use
List<String> result;
List<Process> processes = ProcessBuilder.startPipeline(List.of(
new ProcessBuilder("ls", "-l")
.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE),
new ProcessBuilder("grep", "foo")
.redirectError(ProcessBuilder.Redirect.INHERIT)
));
try(Scanner s = new Scanner(processes.get(processes.size() - 1).getInputStream())) {
result = s.useDelimiter("\\R").tokens().toList();
}
to get the matching lines in a list.
Or, for Windows
List<String> result;
List<Process> processes = ProcessBuilder.startPipeline(List.of(
new ProcessBuilder("cmd", "/c", "dir")
.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE),
new ProcessBuilder("find", "\"foo\"")
.redirectError(ProcessBuilder.Redirect.INHERIT)
));
try(Scanner s = new Scanner(processes.get(processes.size() - 1).getInputStream())) {
result = s.useDelimiter("\\R").tokens().toList();
}
These examples redirect stdin of the first process and all error streams to inherit, to use the same as the Java process.
You can also call .redirectOutput(ProcessBuilder.Redirect.INHERIT) on the ProcessBuilder of the last process, to print the results directly to the console (or wherever stdout has been redirected to).
This question already has answers here:
How to use "cd" command using Java runtime?
(8 answers)
Closed 4 years ago.
I am trying to run a .class file in java. Here's what I've tried:
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("cd target/classes/; java -cp ./ SoundHandler Correct; cd ../../");
I did some googling and the best I could come up with was to tack this on to the end:
pr.getInputStream();
pr.getErrorStream();
pr.getOutputStream();
This did not help. I want to run a .class file in java. Thanks!
You are giving three commands to the runtime to execute - but only one parameter. It is trying to execute it as one command - however such a command does not exist.
If the command consists of multiple elements (command and arguments), they should be passed as a String array, so the runtime can differentiate them. If you are using shell commands, (like cd), then the command should be passed to the shell as a parameter.
Try something like this:
//if you are using unix-like OS. For Windows change sh -c to cmd /k
String[] cmd = new String[] {"sh", "-c", "cd target/classes/ && java -cp ./ SoundHandler Correct"};
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(cmd)
For debugging the process, you can read the command's output on the following way:
InputStream is = pr.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null){
System.out.println("MSG: " + line);
}
A bit of update after some chat conversation: the main idea was working, but classpath needed some investigation.
I'm trying to run other java file using ProcessBuilder class.
I would like to get input of entire path of java file + file name + .java and compile it.
Example, input: C:\Windows\test.java
And then, I store input into String variable FILE_LOCATION and call processbuilder to compile input .java file.
Here is my code:
static String JAVA_FILE_LOCATION;
static String command[] = {"javac", JAVA_FILE_LOCATION};
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
process = new ProcessBuilder(new String[]{"java","-cp",A,B}).start();
But I don't know how to set the parameters.
process = new ProcessBuilder(new String[]{
"java","-cp",A,B}).start();
How should I set that parameter (A, B)?
To answer your exact question, let's say, for instance, your class is in package com.yourcompany.yourproduct and your class file is in /dir/to/your/classes/com/yourcompany/yourproduct/Yourclass.class.
Then A = "/dir/to/your/classes" and B = "com.yourcompany.yourproduct.Yourclass".
However, there's a few things to be aware of. Looking at your code:
static String JAVA_FILE_LOCATION;
static String command[] = {"javac", JAVA_FILE_LOCATION};
ProcessBuilder processBuilder = new ProcessBuilder(command);
No. You need to CD to the directory and then run javac. The easiest way to do that is by calling processBuilder.directory(new File("/dir/to/your/classes")). Then you need to give javac a relative path to your source file ("com/yourcompany/yourproduct/Yourclass.java").
Process process = processBuilder.start();
process = new ProcessBuilder(new String[]{"java","-cp",A,B}).start();
Wait until the first process has finished compiling before you try to run it! Between the two lines above, insert process.waitFor();. You might also want to check for any errors and only run the second process if the first has succeeded.
By the way, there's no need for all that long-hand creation of string arrays. Just use varargs: process = new ProcessBuilder("java", "-cp", A, B).start();.
So for work I would like to automate something for minitab. We get results from our microscope and these need to be put into Minitab. Now I wanted to make a program that does some changes to the text file and then automatically opens minitab with a macro. I have everything working except for the auto opening of the macro with minitab.
I can launch it from cmd manually no problem, so it should be working.
Code can be found below, after compiling and running I get this error
'C:/Program' is not recognized as an internal or external command,
operable program or batch file.
Process finished with exit code 0
Which makes me believe cmd does something like:
cmd.exe,/c,c:/Program,Files/..
instead of
cmd.exe,/c,c:/program files/...
String PathExe = "\"C:/Program Files/Minitab/Minitab 17/Minitab 17/Mtb.exe\"";
String Macro = "\"c:/minitAPP/Import.mtb\"";
ProcessBuilder builder;
builder = new ProcessBuilder("cmd.exe", "/c", PathExe + " " + Macro);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) { break; }
System.out.println(line);
There is no need to use cmd.exe to execute another .exe file. Just execute it directly, without the quotes:
ProcessBuilder builder = new ProcessBuilder(
"C:\\Program Files\\Minitab\\Minitab 17\\Minitab 17\\Mtb.exe",
"c:\\minitAPP\\Import.mtb");
By specifying an entire path as a single argument to ProcessBuilder, you ensure that the operating system will treat it as a single argument, which is the purpose of using quotations marks on a normal command line.
I am using cygwin to get unix environment on windows.
I have some shell script that run on cygwin to perform syncing works and other things. I want to executes these script through java code.
Also during executing of scripts on cygwin , certain information is displayed on terminal by using simple echo command.. I want to show all that information in my application.
How can I do this??
Use the Runtime class to run Cygwin. This is very brittle, and dependent upon your setup, but on my machine I would do:
Runtime r = Runtime.getRuntime();
Process p = r.exec("C:\\dev\\cygwin\\bin\\mintty.exe --exec /cygpath/to/foo.sh");
Then wait for the Process to complete, and get a handle to it's InputStream objects to see what was sent to stdout and stderror.
The first part of the command is to run cygwin, and the second is to execute some script, or command (using -e or --exec). I would test this command on the DOS prompt to see if it works first before cutting any code. Also, take a look at the options available by doing:
C:\dev\cygwin\bin\mintty.exe --help
Also from within the DOS prompt.
EDIT: The following works for me to print version information
public class RuntimeFun {
public static void main(String[] args) throws Exception {
Runtime r = Runtime.getRuntime();
Process p = r.exec("C:\\dev\\cygwin\\bin\\mintty.exe --version");
p.waitFor();
BufferedReader buf = new BufferedReader(
new InputStreamReader(
p.getInputStream()));
String line = buf.readLine();
while (line != null) {
System.out.println(line);
line = buf.readLine();
}
}
}
Unfortunately, can't seem to get it working with --exec, so you're going to have to do some more research there.
You can use something like this
String cmd = "ls -al";
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
pr.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null) {
System.out.println(line);
}
p.s. this doesn't handle errors