I want to execute this command within my java program and check if it was successfully executed.
sudo ntpdate -u someserver.com
I create a bash with the command
#!/bin/sh
sudo ntpdate -u omeserver.com
and execute it with java
ProcessBuilder pb = new ProcessBuilder("/updateTime");
Process p = pb.start();
p.waitFor();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println(stdInput.readLine());
But I get no output, there are no lines in stdInput, how can I check if the command was correctly executed?
If I add for example Echo updated in the end of the bash file I get it in the stdInput, but it still don't mean that the time were updated
You'd probably get by easier when just calling sudo directly with ProcessBuilder instead of an external script. That's just redundant complexity for the task at hand.
You can feed ProcessBuilder with the whole command line, for example, like this:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class q39836547 {
private static String[] cmdl = { "/usr/bin/sudo",
"ntpdate",
"-u",
"some.ntp.server" };
public static void main(String[] as) throws IOException {
ProcessBuilder pb = new ProcessBuilder(cmdl);
Process p = pb.start();
BufferedReader stdin = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stderr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
try { p.waitFor(); }
catch(InterruptedException e) { }
if(p.exitValue() != 0)
System.err.println("The process was not executed successfully.");
else
System.err.println("The process ran and exited cleanly.");
stdin.lines().forEach(s -> System.out.println("STDOUT: " + s));
stderr.lines().forEach(s -> System.out.println("STDERR: " + s));
}
}
You also have to waitFor() (as you properly did) the ntpdate to finish. Otherwise you might end up reading its standard input or standard error with getInputStream() or getErrorStream() before there is any output produced into either stream.
If you comment out the try-catch-block, you'll occasionally see how the process is still running while you're trying to read its input. That is likely to happen almost every time, actually.
Related
I'm on Windows 10, using ProcessBuilder to run a .exe from my Java program and using BufferedReader to get the number it outputs when it's provided the path that my Java program provides. It's working, but it's freezing the program for an unbearable while when it tries to get the output.
It worked smoothly when I tested it on Ubuntu 20, but I can't make it go fast on Windows. Also, if I run the .exe file from cmd, it goes fast as it should.
Here's my Main class code:
package teste;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
Process process;
String command = "src\\teste\\flir_image_extractor.exe -avg -i C:\\Users\\Daniel\\Desktop\\example.jpg";
try {
ProcessBuilder builder = new ProcessBuilder();
if (isWindows) {
builder.command("cmd.exe", "/c", command);
} else {
builder.command("sh", "-c", command);
}
System.out.println("this");
builder.directory(new File(System.getProperty("user.dir")));
builder.redirectErrorStream(true);
process = builder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
System.out.println(line); // Do something with the return
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I tested it with prints, and it hangs just as it enters the while loop, so it looks like readLine() is the issue. Does anyone know what could be slowing it down?
I'm running the code in Eclipse.
I thank you in advance.
A few things to try. It may be the Eclipse console - some versions have been slow if there is a lot of output. You could test this by running this Java app from Windows command line to see if issue goes away, or you could remove your reader.readLine() / System.out.println loop and replace with transferTo:
try(var stdo = p.getInputStream()) {
stdo.transferTo(System.out);
}
Don't forget to wait for the process exit:
int rc = exec.waitFor();
If the Eclipse console is the issue, redirect output to a file before start and check the file afterwards:
pb.redirectOutput(new File("stdout.log"));
Ideally, don't use CMD.EXE / shell to run applications that may be run directly, try as:
String[]command = new String[] {"src\\teste\\flir_image_extractor.exe","-avg", "-i", "C:\\Users\\Daniel\\Desktop\\example.jpg"};
I am using Java to call powershell script. The powershell script is built with function and the function will write values to console. I need to capture those values in java.
my poweshell script is as below
$TokenCSV="M:\work\Powershell\TokenExtractedFromDB_Spec.csv"
$TokenXlPath="M:\work\Powershell\TokenListconverted.xlsx"
$Switch="Token"
Write-Host "Inside ConvertCSVtoEXL2 calling fuc :"
$x=ConverToExlFile $TokenCSV $TokenXlPath $Switch
###Function
function ConverToExlFile
{
Param ([string]$TokenCSV,
[string]$TokenXlPath,
[string]$Switch)
Write-Output "Inside ConverToExlFile Function :"| Out-Null
for($row = 2;$row -lt 10;$row++)
{
Write-Output "Inside for loop :$row"| Out-Null
}
return
}
while calling above code through java i m not getting values in while loop as given below. it just finishes once powershell script executes.
Process proc = runtime.exec("cmd.exe /c powershell.exe M:\\work\\Powershell\\V2\\ConvertCSVtoEXL2.ps1");
System.out.println("2...");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
System.out.println("3");
while ((line = reader.readLine()) != null)
{
System.out.println(line);
//System.out.println(reader.readLine());
System.out.println("4");
}
IT would be great if any one can help me with this.
You don't need cmd.exe. You can directly run powershell.exe.
Your PowerShell script is sending output to Out-Null so obviously nothing will be written to standard output.
powershell.exe accepts a -File parameter which you can use to run your script.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class PrcBldTs {
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("powershell.exe", "-File", "M:\\work\\Powershell\\V2\\ConvertCSVtoEXL2.ps1");
Process p = pb.start();
try (InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr)) {
String line = br.readLine();
while (line != null) {
System.out.println(line);
line = br.readLine();
}
}
int exitStatus = p.waitFor();
System.out.println("exit status = " + exitStatus);
}
}
Note that you must call method waitFor() so that your java code will wait until the PowerShell script terminates.
Remember that ProcessBuilder does not emulate a Windows command prompt. In the ProcessBuilder constructor you need to split the command that you pass into a list of words.
Of-course, if all you want to do is print the PowerShell script output, you can simply call method redirectIO() of class ProcessBuilder. Then the above code becomes:
import java.io.IOException;
public class PrcBldTs {
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("powershell.exe", "-File", "M:\\work\\Powershell\\V2\\ConvertCSVtoEXL2.ps1");
pb.inheritIO();
Process p = pb.start();
int exitStatus = p.waitFor();
System.out.println("exit status = " + exitStatus);
}
}
you can use proc.waitFor(); before getting input stream from proc
I need to start a server using bash, so I had created an UNIX shell , but I am not able to execute it with Java from Eclipse.
I tried the following code which doesn't work :
Process proc = Runtime.getRuntime().exec(./startServer);
Here is content of the startServer file :
#!/bin/bash
cd /Users/sujitsoni/Documents/bet/client
npm start
You can try the following two options.
Option 1
Process proc = Runtime.getRuntime().exec("/bin/bash", "-c", "<Abosulte Path>/startServer");
Option 2
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "<Absolute Path>/startServer");
pb.directory(new File("<Absolute Path>"));
Process proc = pb.start();
A couple Of things can go wrong:
The path to the file you have given might be wrong for eclipse it can take relative path but from the command line, it will take the absolute path.
error=13, Permission denied - If the script file doesn't have required permissions. In your scenario, that might not the case as you are not getting any error.
At last, you are executing the script by java program so the output of your script will not be printed out. In your scenario, this might be the case. You need to capture the output of script from BufferedReade and print it. ( In your case server might have started but you are not seeing the logs/output of the script.
See the code sample below for printing output.
public static void main(String[] args) throws IOException, InterruptedException {
Process proc = Runtime.getRuntime().exec("./startServer");
proc.waitFor();
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println(output);
}
I have a python script and it takes a long time to finish. I would like to run it from Java, but also output the script's output while it is executing, so that I can tell if it is properly running.
I've searched and only found examples where we output the output after the system command has finished, rather than during its execution.
Any way to do it while the script is running?
Here's what I have
public void doSomething() throws IOException {
String[] callAndArgs = {"python", "/hi.py"};
Process p = Runtime.getRuntime().exec(callAndArgs);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
i managed to get it working like this (Note it requires java7):
package test;
import java.lang.ProcessBuilder.Redirect;
public class Test {
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("python","/home/foobar/Programming/test/src/test/test.py");
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
p.waitFor();
}
}
python (note i flush on python to make it work using sys.stdout.flush())
import time,sys
c =0
while c<=50:
time.sleep(1)
print("----")
c = c +1
sys.stdout.flush()
Note if you don't want to flush in a loop you can use this:
ProcessBuilder pb = new ProcessBuilder("python","-u","/home/foobar/Programming/NetBeansProjects/test/src/test/test.py");
Redirect.INHERIT
Indicates that subprocess I/O source or destination will be the same as those of the current process. This is the normal behavior of most operating system command interpreters (shells).
I've searched and only found examples where we output the output after
the system command has finished, rather than during its execution.
That's weird, because your example should be dumping the output as the command is executing.
Instead of using BufferedReader, you could try reading directly from the InputStream instead as the required conditions for readLine might not be being met until after the process exits.
I'd also recommend that you use a ProcessBuilder over Process directly, as, apart from anything else, it allows you to redirect the output from the error stream into the input stream, allowing you to read just one stream instead of two...
This might also be an issue with Python and how it flushes it output buffers...
For example, rather then waiting for the BufferedReader to decide when to return, try printing each character from the stream as it occurs/is reported
ProcessBuilder pb = new ProcessBuilder("test.py");
pb.redirectError();
Process p = pb.start();
InputStream is = null;
try {
is = p.getInputStream();
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char)in);
}
} finally {
try {
is.close();
} catch (Exception e) {
}
}
Update
Doing a little reading, Python seems to be buffering its out out before sending it to the stdout. I don't think you can fix this on the a Java side, but need to alter either the way Python is run or the script works.
See How to flush output of Python print? for more details
I'm suspecting that you are writing to stderr, which you can't see because you are blocking on stdin. Use a ProcessBuilder instead of doing exec. This way, you can redirect stderr and stdin into a single stream.
Here is an example:
import java.io.*;
public class Test {
public static void main(String... args) throws IOException {
ProcessBuilder pb =
new ProcessBuilder("test.py");
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);
}
}
}
Alternatively you can spawn threads to read from stdin/stderr respectively.
Another thing to look for is output buffering by python. You can see if this is the cause by doing:
import sys
sys.stdout.flush()
after you write to stdout
Don't use #readLine as the conditional in your while loop. Instead wrap your inputStream in a scanner and use #hasNextLine()
Scanner in = new Scanner(p.getInputStream());
while (in.hasNextLine()) {
System.out.println(in.nextLine());
}
I have a program which is:
import java.io.*;
import java.util.*;
public class ExecBashCommand {
public static void main(String args[]) throws IOException {
if (args.length <= 0) {
System.err.println("Need command to run");
System.exit(-1);
}
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("./nv0914 < nv0914.challenge");
Process process1 = runtime.exec("echo ${?}");
InputStream is = process1.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
//System.out.printf("Output of running %s is:", Arrays.toString(args));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
note: nv0914 is a bash executable file and nv0914.challenge is a text file.
When i run any normal command in terminal and just after that if I check the exit code using echo ${?}. Now I want to do the same by using a program, but the program is simply giving the output ${?}. Please help me out!
Process.waitFor() returns an int That is where the exit code is returned. If you start an unrelated program, won't have a previous exit code which is why it doesn't return anything useful.
You can't use exitValue() reliably because you could call it before the program has finished. You should only call it after calling waitFor() (and it will give the same exit code waitFor() does)
From the Javadoc for exitValue
Throws: IllegalThreadStateException - if the subprocess represented by this Process object has not yet terminated.