Getting command prompt output instantly? - java

Probably a misleading title, but thanks to people on my other question, I got my program somewhat working, though now not sure what to do.
Here is my method to run command prompt commands and return the output
public static String cmdExec(String cmdLine) {
String line;
String output = "";
try {
Process p = Runtime.getRuntime().exec(cmdLine);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
output += (line + '\n');
}
input.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
return output;
}
It works how I want it to work, though now when I run this method, it is going to wait until everything is done, and then return the output, which is not what I want.
I made a ping flooding method that uses the cmdExec method. Here is how I call cmdExec()
String[] input = ipTextField.getText().split(":");
if(input.length == 2) {
System.out.println(cmdExec("cmd /c ping " + input[0] + " -t -n " + Integer.parseInt(input[1])));
So now for instance, if I type "127.0.0.1:3" in my program, it's going to send 3 packets to localhost. Now the problem here is, instead of printing out the lines I get as output from command prompt 1 by 1, it's going to wait until all the 3 packets are sent, and then print the output full output.
If I type "ping 127.0.0.1 -t -n 3" in command prompt, it's going to print the reply 1 by 1, not all just at once, so how would I go about doing the same in my program?

Instead of
while ((line = input.readLine()) != null) {
output += (line + '\n');
}
To output the results to the command line immediately just print within the while loop
while ((line = input.readLine()) != null) {
System.out.println(line);
output += (line + '\n');
}

You can print out continuously with:
while ((line = input.readLine()) != null) {
System.out.println(line);
output += (line + '\n');
}
(The following is still useful for future viewers, but is not an applicable answer to the question.)
Simply insert a process.waitFor() before reading from the output stream. This command waits until a process dies before continuing. You then don't have to read line by line, either. You can simply dump the buffer all at once.
Either this, or you can find a string which only occurs on the last line (e.g. Minimum in Windows) and change the while condition to:
while((line == input.readline()).indexOf("Minimum") == -1)

Related

Get the Infornation from getRuntime().exec hat java app hangs up

My code so far:
public static void getTasklist(Table table, Login login){
for(TableItem tableItem : table.getItems()){
try {
if(tableItem.getChecked()){
String command = ("cmd.exe /k tasklist /s " + tableItem.getText(3) + " /U .\\" + SettingsManager.getSetting(login, "Current-User") + " /p " + SettingsManager.getSetting(login, SettingsManager.getSetting(login, "Current-User")+"-PW"));
Process p = Runtime.getRuntime().exec(command);
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
}
}
catch (IOException e) {
}
}
}
What I want to do: get task list information from a computer and print it to console (later print it to a window maybe). The host name from the computer comes from the checked table (tableItem.getText(3)) and the credentials comes from something I called settingsmanager (SettingsManager.getSetting....).
What works ATM: I get the Information and it got printed to console but after the last line the app hangs up.. I assume that the while loop never breaks but I am not sure about that..

Java reader does not start printing until closing the programm [duplicate]

I have the following code example below. Whereby you can enter a command to the bash shell i.e. echo test and have the result echo'd back. However, after the first read. Other output streams don't work?
Why is this or am I doing something wrong? My end goal is to created a Threaded scheduled task that executes a command periodically to /bash so the OutputStream and InputStream would have to work in tandem and not stop working. I have also been experiencing the error java.io.IOException: Broken pipe any ideas?
Thanks.
String line;
Scanner scan = new Scanner(System.in);
Process process = Runtime.getRuntime ().exec ("/bin/bash");
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
String input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.close();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
Firstly, I would recommend replacing the line
Process process = Runtime.getRuntime ().exec ("/bin/bash");
with the lines
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilder is new in Java 5 and makes running external processes easier. In my opinion, its most significant improvement over Runtime.getRuntime().exec() is that it allows you to redirect the standard error of the child process into its standard output. This means you only have one InputStream to read from. Before this, you needed to have two separate Threads, one reading from stdout and one reading from stderr, to avoid the standard error buffer filling while the standard output buffer was empty (causing the child process to hang), or vice versa.
Next, the loops (of which you have two)
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
only exit when the reader, which reads from the process's standard output, returns end-of-file. This only happens when the bash process exits. It will not return end-of-file if there happens at present to be no more output from the process. Instead, it will wait for the next line of output from the process and not return until it has this next line.
Since you're sending two lines of input to the process before reaching this loop, the first of these two loops will hang if the process hasn't exited after these two lines of input. It will sit there waiting for another line to be read, but there will never be another line for it to read.
I compiled your source code (I'm on Windows at the moment, so I replaced /bin/bash with cmd.exe, but the principles should be the same), and I found that:
after typing in two lines, the output from the first two commands appears, but then the program hangs,
if I type in, say, echo test, and then exit, the program makes it out of the first loop since the cmd.exe process has exited. The program then asks for another line of input (which gets ignored), skips straight over the second loop since the child process has already exited, and then exits itself.
if I type in exit and then echo test, I get an IOException complaining about a pipe being closed. This is to be expected - the first line of input caused the process to exit, and there's nowhere to send the second line.
I have seen a trick that does something similar to what you seem to want, in a program I used to work on. This program kept around a number of shells, ran commands in them and read the output from these commands. The trick used was to always write out a 'magic' line that marks the end of the shell command's output, and use that to determine when the output from the command sent to the shell had finished.
I took your code and I replaced everything after the line that assigns to writer with the following loop:
while (scan.hasNext()) {
String input = scan.nextLine();
if (input.trim().equals("exit")) {
// Putting 'exit' amongst the echo --EOF--s below doesn't work.
writer.write("exit\n");
} else {
writer.write("((" + input + ") && echo --EOF--) || echo --EOF--\n");
}
writer.flush();
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
System.out.println ("Stdout: " + line);
line = reader.readLine();
}
if (line == null) {
break;
}
}
After doing this, I could reliably run a few commands and have the output from each come back to me individually.
The two echo --EOF-- commands in the line sent to the shell are there to ensure that output from the command is terminated with --EOF-- even in the result of an error from the command.
Of course, this approach has its limitations. These limitations include:
if I enter a command that waits for user input (e.g. another shell), the program appears to hang,
it assumes that each process run by the shell ends its output with a newline,
it gets a bit confused if the command being run by the shell happens to write out a line --EOF--.
bash reports a syntax error and exits if you enter some text with an unmatched ).
These points might not matter to you if whatever it is you're thinking of running as a scheduled task is going to be restricted to a command or a small set of commands which will never behave in such pathological ways.
EDIT: improve exit handling and other minor changes following running this on Linux.
I think you can use thread like demon-thread for reading your input and your output reader will already be in while loop in main thread so you can read and write at same time.You can modify your program like this:
Thread T=new Thread(new Runnable() {
#Override
public void run() {
while(true)
{
String input = scan.nextLine();
input += "\n";
try {
writer.write(input);
writer.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} );
T.start();
and you can reader will be same as above i.e.
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
make your writer as final otherwise it wont be able to accessible by inner class.
You have writer.close(); in your code. So bash receives EOF on its stdin and exits. Then you get Broken pipe when trying to read from the stdoutof the defunct bash.

Joining a thread / process in Java after some time - Java

I have the following method, which executes a command as a process and returns the ouput:
public String execute(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return output.toString();
}
This code is great whenever the command returns, however for continuing running processes such as top this may never return. The code does not need to keep running continuously. It only needs to capture a snapshot, or it could time out after some time, such as 3 seconds. How can I accomplish that?
Process has a method waitFor. It can be used to force a timeout. For example:
if ((p = Runtime.getRuntime().exec(execPath)) != null) && !p.waitFor(TIMEOUT_CONSTANT, TimeUnit.SECONDS)) {
p.destroyForcibly();
}

Java: No input from Process object until the program closes

I'm trying to get input from the console of a .exe process started by a Java script. Nothing appears in the console window, and nothing is read by the program until the process is terminated.
blServ = new ProcessBuilder(blPath + "Blockland.exe", "ptlaaxobimwroe", "-dedicated", "-port " + port, "-profilepath " + blPath.substring(0, blPath.length() - 1)).start();
System.out.println("Attempting to start server...\n" + blPath);
consoleIn = new BufferedReader(new InputStreamReader(blServ.getInputStream()));
'blServ' is a Process object. And yes, the program is starting successfully.
public void blStreamConsole() //called once every 500 milliseconds
{
String lineStr = "";
String line = "";
int lines = 0;
try
{
if (consoleIn != null)
{
while ((line = consoleIn.readLine()) != null)
{
//if (!line.equals("%"));
//{
lineStr += line + wordSym;
lines++;
//}
}
}
}
catch (IOException e)
{
netOut.println("notify" + wordSym + "ERROR: An I/O exception occured when trying to get data from the remote console. Some lines may not be displayed.");
}
if (!lineStr.equals("") && !(lineStr == null))
netOut.println("streamconsole" + wordSym + lines + wordSym + lineStr);
}
Basically, this method sees if there is more input waiting in the consoleIn object, and if there is, it appends every line it has to another string, and that other string is sent to a client. Unfortunately, it is all sent in one big chunk right when Blockland.exe is closed. Sorry about the indenting issues. The Stackoverflow editor re-arranged all of the code.
It seems to me that there are two possibilities here:
readLine blocks, waiting for input (and doesn't return null as you expect). You may be able to fix it by not using BufferedReader and instead using the InputStream
The output stream doesn't flush until all the input has been written. Try putting a flush there:
Also note that if lineStr is null, you'll get a NullPointerException as your code currently is (you need to swap your conditions), but it can't even be null.
if (!lineStr.isEmpty())
{
netOut.println("streamconsole" + wordSym + lines + wordSym + lineStr);
netOut.flush();
}
while ((line = consoleIn.readLine()) != null){
lineStr += line + wordSym;
lines++;
}
The problem with this piece of code is that it will keep running until the program exits. It will append every single line to lineStr until the program exits (when console.readLine() is null). The whole lineStr is then printed afterwards, containing the whole console.
If you want to continuously print the output, you will need to print it immediatly:
while ((line = consoleIn.readLine()) != null){
netOut.println(line);
}
You can run this in one separate thread, and it will keep outputting the console to the output stream until the program exits.

Java issue command in command prompt

I have the following class file. This start a command prompt and print the responses. weird thing is after the first print i.e. dir the subsequent doesn't print. Please advice.
import java.io.*;
public class JavaApplication14 {
static Process p;
public static void main(String[] args) {
try {
String line;
p = Runtime.getRuntime().exec("cmd.exe");
OutputStream stdin = p.getOutputStream();
InputStream stderr = p.getErrorStream();
InputStream stdout = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
String input = "dir";
input += "\n";
writer.write(input);
writer.flush();
while ((line = reader.readLine()) != null) {
System.out.println("Stdout: " + line);
}
input = "cd..";
input += "\n";
writer.write(input);
writer.flush();
input = "dir";
input += "\n";
writer.write(input);
writer.close();
while ((line = reader.readLine()) != null) {
System.out.println("Stdout: " + line);
}
} catch (IOException ex) {
Logger.getLogger(JavaApplication14.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Your (first) while() loop never terminates:
while ((line = reader.readLine()) != null) {
System.out.println("Stdout: " + line);
}
readLine() returns null when the stream is closed, but since your sub process is still running, the stream never gets closed.
To solve this, you can either move the reading part into a separate thread (which requires additional synchronization), or a simpler solution would be to see if a specific line contents is read, for example if the command line prompt was printed by cmd.exe:
while ( !(line = reader.readLine()).startsWith("C:\\") ) {
System.out.println("Stdout: " + line);
}
This should work for your particular use case, and might be sufficient to do some learning - for real applications, you might want to have a look into the Apache Commons Exec project.
You are trying to do fundamentally asynchronous work from just one thread, using synchronous I/O operations. Your approach is bound to fail.
Specifically, readLine() blocks until there is a full line to be read, or until the underlying stream is closed.
You'll have to write quite a bit more code, involving threads, to make this work. This is a pain point in Java.
You could also use the ProcessBuilder, especially its redirectOutput method with the argument value INHERIT, to make the subprocess inherit your main process's stdout. In this scenario you won't have the opportunity to analyze the subprocess's output in Java.

Categories