If I call a command line process like this:
Process proc = Runtime.getRuntime().exec("foo -bar");
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();
How do I enter values in it if it's interactive?
Use proc.getOutputStream() to obtain an OutputStream to which you can write the shell script inputs.
Related
There's a command, that runs an exe, it makes an output and when this command ends, then I should run the upload(); method.
run.command(exe_path, txt_path);
run.start();
TimeUnit.SECONDS.sleep(20);
upload();
How can I replace the static sleep method?
Using a ProcessBuilder, you should be able to call Process.waitFor() to wait for the command to finish.
Process p = new ProcessBuilder("foo.exe", "arg1").start();
// handle any input and output
InputStream stdout = p.getInputStream();
OutputStream stdin = p.getOutputStream();
InputStream stderr = p.getErrorStream();
int ret = p.waitFor(); // <- wait for exit
There is a program I run in Ubuntu terminal, called ProgramABC, which reads a query until user presses CTRL+D, and then writes some data to the standard output. It works perfectly:
/path/ProgramABC >> file.txt [enter]
<here I write my query> [enter]
<and I press CTRL+D>
<data is written to file.txt and ProgramABC closes automatically>
I want to run it from Java. My code doesn't work - it creates the file.txt, but it's empty, so I guess something is wrong with passing my query to the process, and therefore to ProgramABC. What do I do wrong? Here is a part of my code:
ProcessBuilder builder = new ProcessBuilder("bash","-c","/path/program ABC >> file.txt");
builder.directory(new File("/another/path/"));
Process process = builder.start();
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
writer.write("<my query here>");
writer.write((char)4); //it's CTRL+D, right?
writer.flush();
writer.close();
i need to sort a csv file by the first column, which is a timestamp. I've been trying to do this with the following code, but the inputstream of the process p is always just blank:
Process p = Runtime.getRuntime().exec("sort -k1,1 -t, Bucket_Stats.csv");
p.waitFor();
// read this file into InputStream
InputStream in = p.getInputStream();
OutputStream output = new FileOutputStream("Sorted_Bucket_Stats.csv");
System.out.println(IOUtils.copy(in,output));
output.flush();
output.close();
Instead of handling the output in Java, you can use the
-o or --output=FILE
flag of the sort command and pass a filename for the output.
If you pass the same filename as the input, it will be overwritten.
I am running a Shell script using cygwin.
Process p;
InputStream in;
BufferedReader br;
String line;
String cmd;
cmd = "D:/cygwin/bin/bash -c '/bin/test/app.sh" +three_ltr_id+""+mon_code+""+year_code+""+part_no+""+version_no+" '";
System.out.println("EXECUTING: " + cmd);
p = Runtime.getRuntime().exec(cmd);
in = p.getInputStream();
p.waitFor();
br = new BufferedReader(new InputStreamReader(in));
System.out.println("OUT:");
while ((line = br.readLine()) != null) {
System.out.println(line);
System.out.println("SCRIPT EXECUTED PROPERLY");
This is showing EXECUTING and the commands that I passed to script.
If I go inside D:/cygwin/bin/test folder and run the same command it works.
When I run the same command at the command line it won't work.
You need to start reading the input from p.getInputStream() immediately, and keep reading it until there is no more. On Windows, there is little or no buffer in the pipe, and the process will hang once it is filled.
Same is true for the error stream. You could launch threads to read both streams, or there's an option in the way you launch processes to combine regular output and errors, and you can just read them from there.
I need to start external executable in such way that user can interact with program that was just started.
For example in OpenSuse Linux there is a package manager - Zypper. You can start zypper in command mode and give commands like install, update, remove, etc. to it.
I would like to run it from Java code in a way user could interact with it: input commands and see output and errors of the program he started.
Here is a Java code I tried to use:
public static void main(String[] args) throws IOException, InterruptedException {
Process proc = java.lang.Runtime.getRuntime().exec("zypper shell");
InputStream stderr = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
char ch;
while ( (ch = (char)br.read()) != -1)
System.out.print(ch);
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
}
But unfortunately I can only see it's output:
zypper>
but no matter what I write, my input doesn't affect program that was started.
How can I do what want to?
You need to get an output stream in order to write to the process:
OutputStream out = proc.getOuptutStream();
This output stream is piped into the standard input stream of the process, so you can just write to it (perhaps you want to wrap it in a PrintWriter first) and the data will be sent to the process' stdin.
Note that it might also be convenient to get the error stream (proc.getErrorStream) in order to read any error output that the process writes to its stderr.
API reference:
http://download.oracle.com/javase/6/docs/api/java/lang/Process.html
Seems like the converting inside the while condition fails in your example, this seems to work better (I don't run Suse so I haven't tried with Zypper):
public static void main(String[] args) throws IOException, InterruptedException
{
//Process proc = java.lang.Runtime.getRuntime().exec("zypper shell");
Process proc = java.lang.Runtime.getRuntime().exec("ping -t localhost");
InputStream stderr = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
int i;
while ( (i = br.read()) != -1)
{
System.out.print((char) i);
}
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
}
I recently wrapped Google Closure Compiler into a .jar-file which is extracted and used in a Process. This compiler only talks via System.in/out/err. There's a big "gotcha" in connecting pipes together, which is just briefly mentioned in the Process javadoc.
"...failure to promptly write the
input stream or read the output stream
of the subprocess may cause the
subprocess to block, and even
deadlock."
On Mac OS X the buffer is 16k, and if you don't read it promptly as suggested, the process deadlocks. My only solution to this problem ATM, is a rather nasty busy wait.
https://github.com/algesten/googccwrap/blob/master/src/main/java/googccwrap/GoogleClosureCompilerWrapper.java