I need to execute from Java a batch script, which does following
1) Once it is started it performs a lengthy (up to several seconds) task.
2) Thereafter, it displays a prompt "Password:".
3) Then, the user types in the password and presses the Enter key.
4) Then, the script completes its job.
I know how to launch the script from Java, I know how to read output of the batch script in Java, but I don't know how to wait for the password prompt to appear (how I get to know that the batch script is awaiting the password entry).
So, my question is: How to get to know when the batch script has printed the prompt?
At the moment, I have following code:
final Runtime runtime = Runtime.getRuntime();
final String command = ... ;
final Process proc = runtime.exec(command, null, this.parentDirectory);
final BufferedReader input = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
String line = null;
while ((line = input.readLine()) != null) {
LOGGER.debug("proc: " + line);
}
That should do the job:
public static void main(final String... args) throws IOException, InterruptedException {
final Runtime runtime = Runtime.getRuntime();
final String command = "..."; // cmd.exe
final Process proc = runtime.exec(command, null, new File("."));
final BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuilder sb = new StringBuilder();
char[] cbuf = new char[100];
while (input.read(cbuf) != -1) {
sb.append(cbuf);
if (sb.toString().contains("Password:")) {
break;
}
Thread.sleep(1000);
}
System.out.println(sb);
}
This one seems to work:
#Override
public void run() throws IOException, InterruptedException {
final Runtime runtime = Runtime.getRuntime();
final String command = ...;
final Process proc = runtime.exec(command, null, this.parentDirectory);
final BufferedReader input = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
String batchFileOutput = "";
while (input.ready()) {
char character = (char) input.read();
batchFileOutput = batchFileOutput + character;
}
// Batch script has printed the banner
// Wait for the password prompt
while (!input.ready()) {
Thread.sleep(1000);
}
// The password prompt isn't terminated by a newline - that's why we can't use readLine.
// Instead, we need to read the stuff character by character.
batchFileOutput = "";
while (input.ready() && (!batchFileOutput.endsWith("Password: "))) {
char character = (char) input.read();
batchFileOutput = batchFileOutput + character;
}
// When we are here, the prompt has been printed
// It's time to enter the password
if (batchFileOutput.endsWith("Password: ")) {
final BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(proc.getOutputStream()));
writer.write(this.password);
// Simulate pressing of the Enter key
writer.newLine();
// Flush the stream, otherwise it doesn't work
writer.flush();
}
// Now print out the output of the batch script AFTER we have provided it with a password
String line;
while ((line = input.readLine()) != null) {
LOGGER.debug("proc: " + line);
}
// Print out the stuff on stderr, if the batch script has written something into it
final BufferedReader error = new BufferedReader(new InputStreamReader(
proc.getErrorStream()));
String errorLine = null;
while ((errorLine = error.readLine()) != null) {
LOGGER.debug("proc2: " + errorLine);
}
// Wait until the program has completed
final int result = proc.waitFor();
// Log the result
LOGGER.debug("result: " + result);
}
Related
I call the.py file in a basic java project and it takes about 30 seconds to run.
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) {
Process proc;
String line ="";
BufferedReader in;
try {
proc = Runtime.getRuntime().exec("D:\\anaconda\\python.exe " +
"D:/2017/Python/pythonProject8/main.py " +
"D:\\2017\\Python\\pythonProject8\\flower1.jpg");
proc.waitFor();
in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
result:
enter image description here
But this code is skipped when I use spring-boot.
#GetMapping("test")
public String test(){
System.out.println(1);
Process proc;
String line = "";
String result = "";
try {
proc = Runtime.getRuntime().exec("D:\\anaconda\\python.exe " +
"D:/2017/Python/pythonProject8/main.py " +
"D:\\2017\\Python\\pythonProject8\\flower3.jpg");// 执行py文件
proc.waitFor();
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = in.readLine()) != null) {
System.out.println(line);
result += line;
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(2);
return result;
}
result:
enter image description here
I want to know how to run spring-boot properly.
thanks.
If your.py file takes a long time to run then you shouldn't use Process and use ProcessBuilder instead.
public ArrayList<String> getPasswords(String path) throws IOException {
String result = "";
ProcessBuilder processBuilder = new ProcessBuilder("D:\\anaconda\\python.exe ", "D:\\2017\\Python\\pythonProject8\\main.py",path);
//The path here is me.py needs to be passed in
processBuilder.redirectErrorStream(true);
final Process process = processBuilder.start();
final BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s = null;
int i = 0;
while ((s = in.readLine()) != null)//This if is I need to ignore some of the output
{
i++;
if (i >6) {
result += s + '\n';
}
}
if (!result.equals("")){
return new ArrayList<String>(Arrays.asList(result.split("\n")));
}
return new ArrayList<String>();
}
You may run an error "DLL load failed while importing XXXX".
Please update the packages required for python.
I am executing a command which returns me the Revision number of a file; 'fileName'. But if there is some problem executing the command, then the application hangs up. What can I do to avoid that condition? Please find below my code.
String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName;
Process p = Runtime.getRuntime().exec(cmd) ;
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
I guess the issue is that you are only reading InputStream and not reading ErrorStream. You also have to take care that both the streams are read in parallel. It may so happen that currently the data piped from the output stream fills up the OS buffer, your exec command will be automatically be suspended to give your reader a chance to empty the buffer. But the program will still be waiting for the output to process. Hence, the hang occurs.
You can create a separate class to handle both the Input and Error Stream as follows,
public class ReadStream implements Runnable {
String name;
InputStream is;
Thread thread;
public ReadStream(String name, InputStream is) {
this.name = name;
this.is = is;
}
public void start () {
thread = new Thread (this);
thread.start ();
}
public void run () {
try {
InputStreamReader isr = new InputStreamReader (is);
BufferedReader br = new BufferedReader (isr);
while (true) {
String s = br.readLine ();
if (s == null) break;
System.out.println ("[" + name + "] " + s);
}
is.close ();
} catch (Exception ex) {
System.out.println ("Problem reading stream " + name + "... :" + ex);
ex.printStackTrace ();
}
}
}
The way you use it is as follows,
String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName;
Process p = Runtime.getRuntime().exec(cmd) ;
s1 = new ReadStream("stdin", p.getInputStream ());
s2 = new ReadStream("stderr", p.getErrorStream ());
s1.start ();
s2.start ();
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(p != null)
p.destroy();
}
This code is based on the same idea Arham's answer, but is implemented using a java 8 parallel stream, which makes it a little more concise.
public static String getOutputFromProgram(String program) throws IOException {
Process proc = Runtime.getRuntime().exec(program);
return Stream.of(proc.getErrorStream(), proc.getInputStream()).parallel().map((InputStream isForOutput) -> {
StringBuilder output = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(isForOutput))) {
String line;
while ((line = br.readLine()) != null) {
output.append(line);
output.append("\n");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return output;
}).collect(Collectors.joining());
}
You can call the method like this
getOutputFromProgram("cmd /C si viewhistory --fields=revision --project="+fileName);
Note that this method will hang if the program you are calling hangs, which will happen if it requires input.
I'm trying to make a java program which will get the serial of the hard disk thru cmd or terminal. I'm trying it on both OS (Windows, Linux). I'm having trouble with Linux, it returns a whitespace, when I type hdparm -I /dev/sda | grep Serial in the terminal It shows the serial number of the hard drive.
Question how can I get or display the serial number.
here's my code:
private static String OS= System.getProperty("os.name").toLowerCase();
private static String system;
private static String serial;
private void getVol(String drive)
{
String query=new String();
if(isWindows())
{
query="cmd /c"+" vol "+drive+":";
}
else if(isUnix())
{
query="hdparm -I /dev/sda | grep Serial";
}
try
{
Runtime rt=Runtime.getRuntime();
InputStream is=rt.exec(query).getInputStream();
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr);
String line;
if(isWindows())
{
br.readLine();
line=br.readLine();
line=line.substring(line.lastIndexOf(" ")+1);
serial=line;
}
else if(isUnix())
{
line=br.readLine();
serial=line;
}
}catch(IOException ex)
{
ex.printStackTrace();
}
}
private static boolean isWindows() {
return (OS.indexOf("win") >= 0);
}
private static boolean isUnix()
{
return (OS.indexOf("nux") >= 0);
}
public static void main(String args[])
{
MainClass f=new MainClass();
f.getVol("C");
System.out.println(serial);
}
It's being a while since this was posted, but #giusc solution didn't work for me, so posting my research for others.
Get Hard Disk Drive Serial Number on Linux:
public static void main(String[] args) throws Exception {
String sc = "/sbin/udevadm info --query=property --name=sda"; // get HDD parameters as non root user
String[] scargs = {"/bin/sh", "-c", sc};
Process p = Runtime.getRuntime().exec(scargs);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
if (line.indexOf("ID_SERIAL_SHORT") != -1) { // look for ID_SERIAL_SHORT or ID_SERIAL
sb.append(line);
}
}
System.out.println("HDD Serial number:" + sb.toString().substring(sb.toString().indexOf("=") + 1));
}
Get Hard Disk Drive Serial Number (Manufacture) Windows:
public static void main(String[] args) {
String sc = "cmd /c" + "wmic diskdrive get serialnumber";
Process p = Runtime.getRuntime().exec(sc);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
System.out.println("HDD Serial number: " + sb.substring(sb.toString().lastIndexOf("r") + 1).trim());
}
Your problem is almost certainly that running hdparm requires root privileges. It can't be run by a normal user.
Additionally, the "serial number" that you're reading on Windows is the volume serial number of the primary file system, not of the hard drive. It can be changed rather easily (e.g, using VolumeID).
Say I have a function like this :
public String runCommand(parameters, boolean interactive)
{
Process p = null;
// some code
try
{
final ProcessBuilder pb = new ProcessBuilder(my_command);
pb.inheritIO(); // So the output is displayed on the console
p = pb.start();
p.waitFor();
}
catch( IOException | InterruptedException e )
{
e.printStackTrace();
}
if (interactive )
{
return p.exitValue() + "";
}
else
{
// return the stdout of the process p
}
}
What I'm trying to do is to return the standard output of the process I'm running through ProcessBuilder, only if the interactive boolean is set to false. However, I cannot figure how to redirect the standard output to a variable with ProcessBuilder. Please not that I used inheritIO() so when I use a function like adb shell, the shell is displayed in my console, which is the behaviour I want. So basically, as for now, I can see the standard output in the console, but I don't know how to return it in the function so I can use this value as a variable for future stuff.
try this
Process p = new ProcessBuilder(cmd).start();
Reader rdr = new InputStreamReader(p.getInputStream());
StringBuilder sb = new StringBuilder();
for(int i; (i = rdr.read()) !=-1;) {
sb.append((char)i);
}
String var = sb.toString();
What you can do is getting the output as and when the execution, like this:
pb.redirectErrorStream(true);
Process p;
try {
p = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
String output = "";
while((line = in.readLine()) != null) {
log.info(line);
output += line + "\n";
}
return output;
} catch (IOException e) {
// ...
}
return null;
I want to be able to make run a system command on Mac OSX from within Java. My code looks like this:
public void checkDisks() throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec("df -h");
int exitValue = p.waitFor();
System.out.println("Process exitValue:" + exitValue);
BufferedReader reader = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line = reader.readLine();
while (line != null) {
line = reader.readLine();
}
System.out.println(line);
}
This always returns null and an exitValue of 0. Never done this before in Java so any thoughts or suggestions greatly appreciated.
Your code is almost OK, you just misplaced the println
public void checkDisks() throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec("df -h");
int exitValue = p.waitFor();
System.out.println("Process exitValue:" + exitValue);
BufferedReader reader = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line = reader.readLine();
while (line != null) {
line = reader.readLine();
System.out.println(line);
}
}
I believe it's what you're trying to achieve.
try this
public void checkDisks() throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(new String[]{"df","-h"});
int exitValue = p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line;
while ((line=reader.readLine()) != null) {
System.out.println(line);
}
System.out.println("Process exitValue:" + exitValue);
}