I am trying to execute a shell script that takes input with Java.
Here is my code so far...
OutputStreamWriter output;
Process p = new ProcessBuilder(new String[]{"sh", "-c", "/data1/Abhishek/hello.sh"}).start();
output = new OutputStreamWriter(p.getOutputStream());
String line = "";
String text = "";
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
if(line.equals("Enter Your Name: ")) {
String password = "password";
output.write(password);
output.write('\n');
output.flush();
}
text += line;
text += "\n";
}
input.close();
try {
p.waitFor();
} catch (InterruptedException e) {
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
}
Here is the shell script..
#!/bin/bash
read -p "Enter Your Name: " username
echo "Welcome $username!"
However it is not working. The script is still waiting for the input...
What am I doing wrong?
I am trying to use the apktool from a Java program. I'm using this for creating a web service. However this command does not run on the shell from the Java program.
String cmd = "apktool d /home/ridhima/Test.apk" ;
try {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while((line = reader.readLine()) != null)
{
System.out.print(line + "\n");
}
p.waitFor();
}
catch (IOException | InterruptedException e1) {
e1.printStackTrace();
}
The command works perfectly fine directly from the shell.
Thanks but it works fine now. Since apktool is a wrapper script, it is probably not being recognized through the java program. Extracting the apktool.jar directly works.
try {
ProcessBuilder pb = new ProcessBuilder("/home/ridhima/java/jdk1.8.0/bin/java", "-jar", "apktool.jar","d","test.apk");
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}
p.waitFor();
}catch (IOException | InterruptedException e1) {
e1.printStackTrace();
}
You maybe should wait for the process to complete
String cmd = "apktool d /home/ridhima/Test.apk" ;
try {
Process p = Runtime.getRuntime().exec(cmd);
// You maybe should wait for the process to complete
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while((line = reader.readLine()) != null)
{
System.out.print(line + "\n");
}
}
catch (IOException | InterruptedException e1) {
e1.printStackTrace();
}
Or you can use ProcessBuilder for the same task
public class Main {
public static void main(String[] args) throws java.io.IOException, java.lang.InterruptedException {
// Create ProcessBuilder instance for UNIX command ls -l
java.lang.ProcessBuilder processBuilder = new java.lang.ProcessBuilder("ls", "-l");
// Create an environment (shell variables)
java.util.Map env = processBuilder.environment();
env.clear();
env.put("COLUMNS", "3");
processBuilder.directory(new java.io.File("/Users"));
java.lang.Process p = processBuilder.start();
}
}
null from bfr.readLine()
However, there is no problem if I run the python file directly on terminal by firing:
python C:/Machine_Learning/Text_Analysis/Ontology_based.py
The last line in my Python script is >> print(data)
The result of the following code is:
Running Python starts:
First Line: null
Picked up _JAVA_OPTIONS: -Xmx512M
package text_clustering;
import java.io.*;
public class Similarity {
/**
*
* #param args
*
*/
public static void main(String[] args){
try{
String pythonPath = "C:/Machine_Learning/Text_Analysis/Ontology_based.py";
//String pythonExe = "C:/Users/AppData/Local/Continuum/Anaconda/python.exe";
ProcessBuilder pb = new ProcessBuilder("python", pythonPath);
Process p = pb.start();
BufferedReader bfr = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
System.out.println("Running Python starts: " + line);
line = bfr.readLine();
System.out.println("First Line: " + line);
while ((line = bfr.readLine()) != null){
System.out.println("Python Output: " + line);
}
}catch(Exception e){System.out.println(e);}
}
}
Usually when executing commands using ProcessBuilder, PATH variable is not taken into consideration. Your python C:/Machine_Learning/Text_Analysis/Ontology_based.py is directly working in your CMD shell because it can locate the python executable using the PATH variable. Please provide the absolute path to python command in your Java code. In below code replace <Absolute Path to Python> with the path to python command and its libraries. Usually it will something like C:\Python27\python in Windows by default
package text_clustering;
import java.io.*;
public class Similarity {
/**
*
* #param args
*
*/
public static void main(String[] args){
try{
String pythonPath = "C:/Machine_Learning/Text_Analysis/Ontology_based.py";
//String pythonExe = "C:/Users/AppData/Local/Continuum/Anaconda/python.exe";
ProcessBuilder pb = new ProcessBuilder(Arrays.asList("<Absolute Path to Python>/python", pythonPath));
Process p = pb.start();
BufferedReader bfr = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
System.out.println("Running Python starts: " + line);
int exitCode = p.waitFor();
System.out.println("Exit Code : "+exitCode);
line = bfr.readLine();
System.out.println("First Line: " + line);
while ((line = bfr.readLine()) != null){
System.out.println("Python Output: " + line);
}
}catch(Exception e){System.out.println(e);}
}
}
Reading from stdin returns null when the script is killed/dies. Do a Process#waitFor and see what the exitValue is. If it isn't 0 then it's highly probable that your script is dying.
I'd try making it work with a dumb script that only writes a value. Make sure that you print all error information from python.
try {
Process p = Runtime.getRuntime().exec(
"python D://input.py ");
BufferedReader in = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
p.waitFor();
} catch (Exception e) {
}
try {
ProcessBuilder pb = new ProcessBuilder("C:/Python27/python", "D://searchTestJava//input.py");
Process p = pb.start();
BufferedReader bfr = new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println(".........start process.........");
String line = "";
while ((line = bfr.readLine()) != null) {
System.out.println("Python Output: " + line);
}
System.out.println("........end process.......");
} catch (Exception e) {
System.out.println(e);
}
I tried this one. This script runs a python file with the argument in Java. It also logs about which line, your program is executing. Hope this Helps.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
public class Test {
public static void main(String... args) throws IOException {
ProcessBuilder pb =
new ProcessBuilder("python","samples/test/table_cv.py","1.pdf");
pb.redirectErrorStream(true);
Process proc = pb.start();
Reader reader = new InputStreamReader(proc.getInputStream());
BufferedReader bf = new BufferedReader(reader);
String s;
while ((s = bf.readLine()) != null) {
System.out.println(s);
}
}
}
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'm using the runtime to run command prompt commands from my Java program. However, I'm not aware of how I can get the output the command returns.
Here is my code:
Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-send" , argument};
Process proc = rt.exec(commands);
I tried doing System.out.println(proc); but that did not return anything. The execution of that command should return two numbers separated by a semicolon. How could I get this in a variable to print out?
Here is the code I'm using now:
String[] commands = {"system.exe", "-get t"};
Process proc = rt.exec(commands);
InputStream stdIn = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stdIn);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<OUTPUT>");
while ((line = br.readLine()) != null)
System.out.println(line);
System.out.println("</OUTPUT>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
But I'm not getting anything as my output, but when I run that command myself it works fine.
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;
}
If use are already have Apache commons-io available on the classpath, you may use:
Process p = new ProcessBuilder("cat", "/etc/something").start();
String stderr = IOUtils.toString(p.getErrorStream(), Charset.defaultCharset());
String stdout = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
At the time of this writing, all other answers that include code may result in deadlocks.
Processes have a limited buffer for stdout and stderr output. If you don't listen to them concurrently, one of them will fill up while you are trying reading the other. For example, you could be waiting to read from stdout while the process is waiting to write to stderr. You cannot read from the stdout buffer because it is empty and the process cannot write to the stderr buffer because it is full. You are each waiting on each other forever.
Here is a possible way to read the output of a process without a risk of deadlocks:
public final class Processes
{
private static final String NEWLINE = System.getProperty("line.separator");
/**
* #param command the command to run
* #return the output of the command
* #throws IOException if an I/O error occurs
*/
public static String run(String... command) throws IOException
{
ProcessBuilder pb = new ProcessBuilder(command).redirectErrorStream(true);
Process process = pb.start();
StringBuilder result = new StringBuilder(80);
try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())))
{
while (true)
{
String line = in.readLine();
if (line == null)
break;
result.append(line).append(NEWLINE);
}
}
return result.toString();
}
/**
* Prevent construction.
*/
private Processes()
{
}
}
The key is to use ProcessBuilder.redirectErrorStream(true) which will redirect stderr into the stdout stream. This allows you to read a single stream without having to alternate between stdout and stderr. If you want to implement this manually, you will have to consume the streams in two different threads to make sure you never block.
Also we can use streams for obtain command output:
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
String[] commands = {"free", "-h"};
Process process = runtime.exec(commands);
BufferedReader lineReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
lineReader.lines().forEach(System.out::println);
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
errorReader.lines().forEach(System.out::println);
}
#Senthil and #Arend answer (https://stackoverflow.com/a/5711150/2268559) mentioned ProcessBuilder. Here is the example using ProcessBuilder with specifying environment variables and working folder for the command:
ProcessBuilder pb = new ProcessBuilder("ls", "-a", "-l");
Map<String, String> env = pb.environment();
// If you want clean environment, call env.clear() first
//env.clear();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
File workingFolder = new File("/home/user");
pb.directory(workingFolder);
Process proc = pb.start();
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);
Create class :
public class Utils {
public static final String SHEL_EXECUTE_ERROR = "SHEL_EXECUTE_ERROR";
public static String shellExec(String cmdCommand) {
final StringBuilder stringBuilder = new StringBuilder();
try {
final Process process = Runtime.getRuntime().exec(cmdCommand);
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line);
}
} catch (Exception e) {
return SHEL_EXECUTE_ERROR;
}
return stringBuilder.toString();
}
}
and use:
final String shellExec = shellExec("cmd /c ver");
final String versionOS = shellExec.equals(SHEL_EXECUTE_ERROR) ? "empty" : shellExec;
If you write on Kotlin, you can use:
val firstProcess = ProcessBuilder("echo","hello world").start()
val firstError = firstProcess.errorStream.readBytes().decodeToString()
val firstResult = firstProcess.inputStream.readBytes().decodeToString()
Adapted from the previous answer:
public static String execCmdSync(String cmd, CmdExecResult callback) throws java.io.IOException, InterruptedException {
RLog.i(TAG, "Running command:", cmd);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
//String[] commands = {"system.exe", "-get t"};
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
StringBuffer stdOut = new StringBuffer();
StringBuffer errOut = new StringBuffer();
// 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);
stdOut.append(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);
errOut.append(s);
}
if (callback == null) {
return stdInput.toString();
}
int exitVal = proc.waitFor();
callback.onComplete(exitVal == 0, exitVal, errOut.toString(), stdOut.toString(), cmd);
return stdInput.toString();
}
public interface CmdExecResult{
void onComplete(boolean success, int exitVal, String error, String output, String originalCmd);
}
Pretty much the same as other snippets on this page but just organizing things up over an function, here we go...
String str=shell_exec("ls -l");
The Class function:
public String shell_exec(String cmd)
{
String o=null;
try
{
Process p=Runtime.getRuntime().exec(cmd);
BufferedReader b=new BufferedReader(new InputStreamReader(p.getInputStream()));
String r;
while((r=b.readLine())!=null)o+=r;
}catch(Exception e){o="error";}
return o;
}
Process p = Runtime.getRuntime().exec("ping google.com");
p.getInputStream().transferTo(System.out);
p.getErrorStream().transferTo(System.out);
Try reading the InputStream of the runtime:
Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-send", argument};
Process proc = rt.exec(commands);
BufferedReader br = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
String line;
while ((line = br.readLine()) != null)
System.out.println(line);
You might also need to read the error stream (proc.getErrorStream()) if the process is printing error output. You can redirect the error stream to the input stream if you use ProcessBuilder.