I am a little confused about why I can't run the following command ls -l
If I run ls or pwd it works fine.
Am I missing something?
ProcessBuilder pb = new ProcessBuilder("ls -l");
pb.redirectErrorStream(true);
Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ( (line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
One more question: How can I run multiple system commands concurrently? Using while loop or for loops will run the command one by one. Any advice?
Thanks in advance.
Change:
new ProcessBuilder("ls -l");
To:
new ProcessBuilder("ls", "-l");
String[] st = {"ls", "bin"};
ProcessBuilder pb = new ProcessBuilder(st);
pb.redirectErrorStream(true);
Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ( (line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
Using while loop or for loops will run the command one by one.
Only when you are doing the whole start-then-read-stdout business for each one of them, one-by-one. The processes are indeed run in parallel, it's just the reading part that's stopping you from running them concurrently. All you need to do is breaking the start and read into two parts:
Stream.of(Arrays.asList("ls", "-l"),
Arrays.asList("python", "-h"),
Arrays.asList("df"))
.map(cmd->{
// Create a process for each command, but don't read the output
try {
return new AbstractMap.SimpleImmutableEntry<>(cmd,
new ProcessBuilder(cmd)
.redirectErrorStream(true)
.start().getInputStream());
} catch (IOException e) {
e.printStackTrace();
return null;
}
})
.filter(p->p!=null)
.parallel()
.forEach(in->{
// Read and print STDOUT for each process.
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in.getValue()))){
String line;
while ((line = reader.readLine()) != null) {
System.out.printf("%20s: %s\n", in.getKey(), line);
}
} catch (IOException e) {
e.printStackTrace();
}
});
The parallel() call is making the output really hard to read, it's there only to demonstrate that the processes are really running concurrently.
Related
I'm trying to run an executable file created from a cpp program in java. If I double-click the exe file, it works just fine, but if I run the file using ProcessBuilder, it gets stuck for some reason, it prints most of the expected output and doesn't continue, also making the entire Java program not responding.
here's my code:
String filePath = FirstScreenController.getFile().getPath();
ProcessBuilder launcher = new ProcessBuilder("ClusteringProgram\\Release\\main.exe",filePath);
launcher.redirectErrorStream(true);
try {
/*File file = FirstScreenController.getFile();
Path newPath = Paths.get(System.getProperty("user.dir")+"\\ClusteringProgram").resolve("K12.fasta");//Moving the file to the
Files.copy(Paths.get(file.getPath()), newPath, StandardCopyOption.REPLACE_EXISTING);*/
System.out.println("Execution started");
p = launcher.start();
InputStream stderr = p.getInputStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
p.waitFor();//Waiting for the process to finish running
System.out.println("Execution completed");
} catch (IOException | InterruptedException e) {e.printStackTrace();}
Close your stream. That's what's causing you to hang. I write code like this quite a bit.
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close(); // You need this or p can hang
p.waitFor();
In addition, you called launcher.redirectStandardError(true); so you actually need all this to gather both stdout and stderr together: The whole rest of this answer is wrong. I don't know what is causing the deadlock. I'm leaving the large code fragment here in case it's some strange library bug and it turns out that the dual-thread reading technique is required to work around it.
final object lock = new object();
InputStream stdout = p.getInputStream();
InputStreamReader isr = new InputStreamReader(stdout);
BufferedReader br = new BufferedReader(isr);
final InputStream stderr = p.getErrorStream();
one = new Thread() {
public void run() {
InputStreamReader isr2 = new InputStreamReader(stderr);
BufferedReader br2 = new BufferedReader(isr2);
while ((line2 = br2.readLine()) != null) {
synchronized(lock) {
System.out.println(line2);
}
}
br2.close(); // you need this or p can hang
}
};
one.start();
while ((line = br.readLine()) != null) {
synchronized(lock) {
System.out.println(line);
}
}
br.close(); // You need this or p can hang
for (;;) {
try {
one.join();
break;
} catch (InterruptedException v) {
/* if there's something that might want the main thread's attention handle it here */
}
}
p.waitFor();
My problem is, after opening cmd from java code, i want user to be able to input like in c++ ms dos applications. When user writes sth such as "dir" or "cd..", i want to execute these codes by java.
The problem is for every command java re-opens cmd again. Also i cannot execute commands. My cmd start code is below ;
final ArrayList<String> commands = new ArrayList<>();
commands.add("cmd.exe");
commands.add("/C");
commands.add("start");
ProcessBuilder pb = new ProcessBuilder(commands);
Process process = pb.start();
Here's some cleaned up code from How to open the command prompt and insert commands using Java?
public static void main(String[] args) {
try {
String ss = null;
Runtime obj = null;
Process p = Runtime.getRuntime().exec("cmd.exe");
//write a command to the output stream
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
writer.write("dir");
writer.flush();
//Get the input and stderror
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("Here is the standard output of the command:\n");
while ((ss = stdInput.readLine()) != null) {
System.out.println(ss);
}
System.out.println("Here is the standard error of the command (if any):\n");
while ((ss = stdError.readLine()) != null) {
System.out.println(ss);
}
} catch (IOException e) {
System.out.println("FROM CATCH" + e.toString());
}
}
I'm trying to execute myfile.jar using another java program which as follows. When the myfile.jar is executed standalone in console, it will as two questions:
Start the load process (y/n)?
Start the patch process (y/n)?
I will pass y to 1st and n to 2nd question. The same thing I'm trying to do using the following java program and it successfully passes answer to the 1st question, but waiting at the 2nd question.
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "myfile.jar", "arg1");
pb.redirectErrorStream(true);
Process p = pb.start();
InputStream in = p.getInputStream();
InputStreamReader ins = new InputStreamReader(in);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(p.getOutputStream());
BufferedReader br = new BufferedReader(ins);
String line = null;
out.write("y\n");
out.write("n\n");
out.flush();
while ((line = br.readLine()) != null) {
System.out.println(line);
}
out.close();
p.waitFor();
p.destroy();
Note: The myfile.jar uses Scanner to take the input from the user.
I guess I found the solution to my question. For future reference, the following is the final program that I've used to solve my problem:
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "myfile.jar", "arg1");
pb.redirectErrorStream(true);
Process p = pb.start();
InputStream in = p.getInputStream();
InputStreamReader ins = new InputStreamReader(in);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(p.getOutputStream());
BufferedReader br = new BufferedReader(ins);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
if (line.contains("Start the load process (y/n)?")) {
out.write("y");
out.newLine();
out.flush();
}
if (line.contains("Start the patch process (y/n)?")) {
out.write("n");
out.newLine();
out.flush();
}
}
out.close();
p.waitFor();
p.destroy();
We are trying to call a Powershell script via Java but it hangs when we try to read the output of that script. It hangs on "input.readLine()"
Here is a code we have tried:
String command = "cmd /c powershell C:\\_checkouts\\TestPowerShell\\passwordExpirationTime.ps1";
Process p = Runtime.getRuntime().exec(command);
new InputStreamReader(p.getInputStream());
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();;
for (String line = input.readLine(); line != null; line = input.readLine()) {
stringBuilder.append(line);
}
input.close();
String msg = stringBuilder.toString();
System.out.println("msg: " + msg);
We tried looking at this solution Java program hangs when trying to invoke powershell script
but none of those suggestions worked for us.
We also tried it without cmd /c and with cmd /k. We really want this as a generic class where any script could be called. i.e. BAT, BASH, SH, Powershell, etc.
Any ideas?
Thanks to the answer below here is the code that worked:
try{
final ProcessBuilder pb = new ProcessBuilder("powershell","C:\\psFile.ps1");
pb.redirectInput(Redirect.from(new File("NUL")));
final Process p = pb.start();
final int retcode = p.waitFor();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}catch (Exception e){
e.printStackTrace();
}
Here's some additional information. Our powershell was returning an error because it was restricted. That is why we needed all the Redirect to NUL. Once we fixed that and it wasn't returning an error we were able to simplify our code to this:
try{
final ProcessBuilder pb;
pb = new ProcessBuilder(args);
final Process p = pb.start();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}catch (Exception e){
e.printStackTrace();
}
Use a ProcessBuilder. Any process implying a modicum of I/O should outright refuse to run via Runtime.exec(), alas, it cannot detect that. And Oracle hasn't flagged it as #Deprecated which is a pity.
Anyway:
final File logFile = new File("/path/to/logfile");
final ProcessBuilder pb = new ProcessBuilder("powershell", "/path/to/the/ps1");
pb.redirectOutput(Redirect.to(logFile));
pb.redirectErrorStream(true);
final Process p = pb.start();
final int retcode = p.waitFor();
// deal with retcode
// read result from the log file
I want to get the IP address of logged in user of the telnet session
So I have written the following code:
Process p1 = Runtime.getRuntime().exec(new String[] {"/usr/bin/who", "-m"});
p1.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p1.getInputStream()));
String line = reader.readLine();
System.out.println("line=" + line);
reader.close();
But I am getting the output as "null".
Where as expected output is:
linus pts/1 Dec 10 03:48 (172.21.235.48)
In this case you shouldn't pass the -m option.
This works for me :
Process p1 = Runtime.getRuntime().exec(new String[] {"/usr/bin/who"});
Try to consume the input stream from the process before calling waitFor().
You can create a shell script which will receive parameter (option) from your java program.
Then you can run your shell script from java like this -
ProcessBuilder pb = new ProcessBuilder("/PATH/test.sh","-m");
String line;
Process process=pb.start();
java.io.InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null)
{
System.out.println(line);
}
return br;
Now in test.sh, you cab grab the argument and run the command -
/usr/bin/who $1 (needs to check, not sure)
Hope this helps.
Thanks guys for the replies.
From the reply of "dystroy" I understood that -m was creating problem.
I tried --m and it worked :)
Please try this code. It's working for me and returns the same output as who -m UNIX command.
import java.io.*;
public class UserPB
{
public static void main(String[] args)
{
try {
// ProcessBuilder pb = new ProcessBuilder("/u01/app/chdir/user.sh");
ProcessBuilder pb = new ProcessBuilder("who");
Process p;
p = pb.start();
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println("Your Host Details--->"+input.readLine());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}