Java spawn new cmd.exe and get the output stream - java

I'm trying to spawn a new console in java and get the ouput stream.
I tried this way :
Process p = Runtime.getRuntime().exec("cmd.exe /c start");
BufferedWriter out = new BufferedWriter( new OutputStreamWriter(
p.getOutputStream()));
the console spawn but i'm not able to write something on the stream !
The other way :
Process p = Runtime.getRuntime().exec("cmd.exe");
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
p.getOutputStream()));
This time i can write to the stream, but the console is not spawning !
I lack knowledge :/
Thank you in advance.

In your first way you started cmd and it started another process which you have no access too. Don't use this way if you need input/output stream.
The other way is right. Process is running fine. But you didn't provide any input for it. Obtain input stream and send some commands like "cd foo\n", "dir\n". As you can see this is regular stream so it requires to execute the command. Then you can use output stream too.
There are a lot of examples how to do so.

Related

Compiling python program using java file and reading input for python program from the file

I've stored my python code in file and then input is passed through input.txt.
String rollno="13F127";
String file="add";
Process p = Runtime.getRuntime().exec("C:\\Python34\\python C:\\Users\\Raga\\Documents\\"+rollno+"\\"+file+".py < C:\\Users\\Raga\\Documents\\"+rollno+"\\input.txt");
When I run it using jsp file, it takes long time to load and output didnt come. Please help me with this.
I've read this process output using buffered and input reader.
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
Please help me with this!
Do not use redirections (<, >, or |) with exec!
The redirections are read and translated by the interactive shells (here cmd.exe) where they read a command from their standard input. The shell then opens the relevant files and calls the program with redirected standard streams.
exec just does this last part, and passes the < ...input.text as two arguments to the Python program... that do not processes them and also passes them to the script that do not process them either! So the child tries to read on standard input, and keeps waiting here.
So you should:
use ProcessBuilder which according to Runtime javadoc is now the preferred way to start a process with a modified environment
redirect input stream for the subprocess to the file
More or less:
ProcessBuilder pb = new ProcessBuilder("C:\\Python34\\python",
"C:\\Users\\Raga\\Documents\\"+rollno+"\\"+file+".py");
pb.redirectInput(Redirect.fromFile("C:\\Users\\Raga\\Documents\\"+rollno+"\\input.txt"));
Process p = pb.start();

Read File to Process Stdin ProcessBuilder

How do I pipe a file into the stdin of a process using ProcessBuilder? The program I am reading the stream from is written in C, but I do not know anything else about it.
Here is the relevant java:
ProcessBuilder pb = new ProcessBuilder("./program").inheritIO();
Process p = pb.start();
DataInputStream din = new DataInputStream(new FileInputStream("./my-file.txt"));
byte[] dinBytes = new byte[din.available()];
din.readFully(dinBytes);
din.close();
OutputStream os = p.getOutputStream();
os.write(dinBytes);
os.close();
int rc = p.waitFor();
System.out.println("RC: " + rc);
Which returns the following error:
java.io.IOException: Stream closed
at java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:434)
at java.io.OutputStream.write(OutputStream.java:116)
at java.io.OutputStream.write(OutputStream.java:75)
at Test.main(Test.java:14)
$ input in flex scanner failed
The cause for your error is the call to .inheritIO() when you build the process. This causes all the process's standard file descriptors to be inherited from the Java process. The documentation says:
This is a convenience method. An invocation of the form
pb.inheritIO()
behaves in exactly the same way as the invocation
pb.redirectInput(Redirect.INHERIT)
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT)
And the documentation for redirectInput(Redirect) says:
If the source is Redirect.PIPE (the initial value), then the standard input of a subprocess can be written to using the output stream returned by Process.getOutputStream(). If the source is set to any other value, then Process.getOutputStream() will return a null output stream.
So, basically, the default is that there is a pipeline between the Java process and the built process, so that you can push in data from your program to the process. But you released the standard input of the process from the pipe and let it wait for input from the user console, but then you tried to treat it as if it's still part of the pipe, and get your end of the pipe in order to push data inside. You get a null output stream, and as soon as you try to put something in it, you get an exception.
So you shouldn't make that call. And since you want input from a text file, the easiest thing to do would actually be to redirect that input stream to the file directly. Again, redirecting breaks the pipe - but you won't need it because the redirection actually does what you need:
// Take input from a file, output and error go to user console
pb = new ProcessBuilder("./program")
.redirectInput(new File("./my-file.txt"))
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process p = pb.start();
int rc = p.waitFor();
An alternative method, in case you want to pipe in more than one file, is to keep the pipe to the process standard input around, but copy the files using Files:
pb = new ProcessBuilder("./program")
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process p = pb.start();
OutputStream os = p.getOutputStream();
Files.copy( Paths.get("./my-file-1.txt"), os );
Files.copy( Paths.get("./my-file-2.txt"), os );
// more files
os.close();
int rc = p.waitFor();
Regarding the DataInputStream: it is a type of InputStream used for processing binary data that was written from a DataOutputStream - with ints, doubles etc. written in binary form. Of course, like any InputStream, you can read bytes from it as-is. But for that, you don't really need to wrap it in a DataInputStream.

Maintaining session while executing shell commands using a java program

We are working on a requirement to execute shell commands from java swing UI.
We need to execute one command to start the session, once the session is started we need to execute some common commands repeatedly.
We are able to execute the commands using the below command.
Runtime.getRuntime().exec("setSession")
Runtime.getRuntime().exec("execute individual task");
this way, everytime we have to set the session and executing the individual tasks.
Is there any way to execute a command (like setSession) once and retain the session to execute the remaining commands?
If I got Your task right, You might want to start a shell on the underlying system, get it's input and output streams and issue Your commands there.
Though that makes You operation system dependent. But commands You executing probably are anyway.
Something like:
Process p = Runtime.getRuntime().exec("cmd.exe");
OutputStream outputStream = p.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
InputStream inputStream = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
writer.write("dir \n");
writer.flush();

ProcessBuilder running processes in foreground

I want to run an executable written in C++ and to see the cmd promt associated with it in foreground, since the executable prints some lines in the cmd.
I have written the following code, but all processes are created and run in background (In this code I open the dummy cmd.exe process, not my process).
Process p = new ProcessBuilder("C:\\Windows\\System32\\cmd.exe").start();
How can i enable foreground running of processes?
Thanks!
The issue is not whether the process is in the foreground or background. When you start a process using Java, you have to use Java to control that process' lifecyle. The Java API provides you access to various attributes of the process. What you're interested in here is the output of the process. That is represented by the process' InputStream. It seems counterintuitive, but it makes sense because from the perspective of your Java program, the process' output is the program's input. Conversely, if you need to send data to the process, you write to the process' OutputStream.
To sum up, access the process' InputStream and print that out to the command-line:
Process process = new ProcessBuilder("C:\\Path\\To\\My\\Application.exe").start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line);
}
System.out.println(line);
This code, of course, assumes that your process is not waiting for any input, i.e., it is not interactive.
Vivin Paliath's answer is really the way to go, then you can do whatever you want with the output, display it in your own dialogue, log it, interpret it, check for errors or whatever.
But just in case you really want that command window showing up. Execute cmd.exe and get the process' OutputStream and write the command (application.exe) to it ending with a new line.
Something along the lines of:
Process p = new ProcessBuilder("C:\\Windows\\System32\\cmd.exe").start();
out = p.getOutputStream();
out.write("path\\application.exe\r\n".getBytes());
out.flush();
Should usually drain the input stream too though anyway.

Running a batch file in Java on a remote server

I'm trying to use Java to interface with a large batch file that uses psexec to execute commands on remote servers.
I'm able to launch the file using process builder and it works fine for most commands, but seems to be getting hung up.
One particular command from the batch file is as follows:
ECHO .
Echo Which would you like to reboot?
Echo 1-10. For computers, enter computer number.
Echo E. Exit
set /p userinp=choose a number(0-22):
but from Java I get:
.
Which would you like to reboot?
1-10. For computers, enter computer number.
E. Exit
and then it hangs
It's clearly not reading the set line, but more importantly I haven't yet figured out how to pass input back to the subprocess.
String[] command = {"cmd", "/c", "batchfile", "restart"};
ProcessBuilder builder = new ProcessBuilder(command);
builder.directory(new File("C:\\"));
Process process = builder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
Any input would be appreciated.
Your batch job requires that you actually provide input in order to proceed, which is why it appears to 'hang'. You need to supply this input to the process, via its output stream. A highly simplified example:
PrintWriter writer = new PrintWriter(process.getOutputStream());
writer.println("10");
writer.flush();
Your process doesn't hang, it is just waiting for some input at the command line, before to proceed.
As you are reading the output from the process via Process.getInputStream(), you can send input back to it using Process.getOutputStream().
public abstract OutputStream getOutputStream()
Gets the output stream of the subprocess. Output to the stream is piped into the standard input stream of the process represented by this Process object.
Implementation note: It is a good idea for the output stream to be buffered.
Returns:
the output stream connected to the normal input of the subprocess.

Categories

Resources