Use Process.getInputStream() to get an InputStream that represents the stdout of the newly created process.
Note that starting/running external processes from Java can be very tricky and has quite a few pitfalls.
They are described in this excellent article, which also describes ways around them.
Answer from Joachim Sauer on Stack OverflowUse Process.getInputStream() to get an InputStream that represents the stdout of the newly created process.
Note that starting/running external processes from Java can be very tricky and has quite a few pitfalls.
They are described in this excellent article, which also describes ways around them.
To collect the output you could do something like
Process p = Runtime.getRuntime().exec("my terminal command");
p.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line = "";
String output = "";
while ((line = buf.readLine()) != null) {
output += line + "\n";
}
System.out.println(output);
This would run your script and then collect the output from the script into a variable. The link in Joachim Sauer's answer has additional examples of doing this.
Videos
The primary reason why this doesn't work is that `$2` is not the same as `ls -1 | tail -1`, even when $2 is set to that string.
If your script accepts a literal string with a command to execute, you can use eval to do so.
I created a complete example. Please copy-paste it and verify that it works before you try applying any of it to your own code. Here's Test.java:
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
String[] command = { "./myscript", "key", "ls -t | tail -n 1" };
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String s;
while ((s = reader.readLine()) != null) {
System.out.println("Script output: " + s);
}
}
}
And myscript:
#!/bin/bash
key="$1"
value=$(eval "$2")
echo "The command $2 evaluated to: $value"
Here's how we can run myscript separately:
$ ls -t | tail -n 1
Templates
$ ./myscript foo 'ls -t | tail -n 1'
The command ls -t | tail -n 1 evaluated to: Templates
And here's the result of running the Java code:
$ javac Test.java && java Test
Script output: The command ls -t | tail -n 1 evaluated to: Templates
As other posters pointed out already, the sub-process is not started in a shell, so the she-bang is not interpreted.
I got your example to work by explicitly starting the evaluation of the second parameter in a shell in jj.sh:
value=`sh -c "$2"`
Not nice, but works.
Other option may be to start the script in a shell explicitly, emulating the sh-bang:
String[] cmd = { "/bin/sh", "jj.sh" , key,value};
You can use java.lang.Runtime.exec to run simple code. This gives you back a Process and you can read its standard output directly without having to temporarily store the output on disk.
For example, here's a complete program that will showcase how to do it:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class testprog {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec("ls -aF");
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
}
}
When compiled and run, it outputs:
line: ./
line: ../
line: .classpath*
line: .project*
line: bin/
line: src/
exit: 0
as expected.
You can also get the error stream for the process standard error, and output stream for the process standard input, confusingly enough. In this context, the input and output are reversed since it's input from the process to this one (i.e., the standard output of the process).
If you want to merge the process standard output and error from Java (as opposed to using 2>&1 in the actual command), you should look into ProcessBuilder.
You can also write a shell script file and invoke that file from the java code. as shown below
{
Process proc = Runtime.getRuntime().exec("./your_script.sh");
proc.waitFor();
}
Write the linux commands in the script file, once the execution is over you can read the diff file in Java.
The advantage with this approach is you can change the commands with out changing java code.
Here is the way to go:
Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-get t"};
Process proc = rt.exec(commands);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(proc.getErrorStream()));
// Read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// Read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
Read the Javadoc for more details here. ProcessBuilder would be a good choice to use.
A quicker way is this:
public static String execCmd(String cmd) throws java.io.IOException {
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
Which is basically a condensed version of this:
public static String execCmd(String cmd) throws java.io.IOException {
Process proc = Runtime.getRuntime().exec(cmd);
java.io.InputStream is = proc.getInputStream();
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
String val = "";
if (s.hasNext()) {
val = s.next();
}
else {
val = "";
}
return val;
}
I know this question is old but I am posting this answer because I think this may be quicker.
Edit (For Java 7 and above)
Need to close Streams and Scanners. Using AutoCloseable for neat code:
public static String execCmd(String cmd) {
String result = null;
try (InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
Scanner s = new Scanner(inputStream).useDelimiter("\\A")) {
result = s.hasNext() ? s.next() : null;
} catch (IOException e) {
e.printStackTrace();
}
return result;
}