Using CMD as a Process
I'm trying to run commands straight through the CMD on Windows (Terminal on Linux). I have the following code. It's acting very strangely. First, when run the program does not print anything. Second, when debugged and stepped through, the program prints the default CMD text and input line. Finally, I can't seem to write to the CMD so it'll execute commands. Here's my code. I'm guessing it may be a threading issue, but I'm not familiar with Runtime.
Runtime r = Runtime.getRuntime();
try {
Process p = r.exec("cmd");
InputStream iStream = p.getInputStream();
开发者_StackOverflow中文版 BufferedReader sReader = new BufferedReader(new InputStreamReader(iStream));
while(sReader.ready()) {
System.out.print((char)sReader.read());
}
OutputStream oStream = p.getOutputStream();
BufferedWriter sWriter = new BufferedWriter(new OutputStreamWriter(oStream));
sWriter.write("mkdir test");
sWriter.newLine();
while(sReader.ready()) {
System.out.print((char)sReader.read());
}
} catch(Exception e) {
e.printStackTrace();
}
And my output when debugged and stepped through, (no output displayed when its run)
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
D:\workspaces\Maven\Command Line>
There could be a couple of things going on. One is that arguments are not getting passed correctly the way you are executing the process. The other, like @zacheusz mentioned, is that output may be coming out from the error stream instead of the input stream.
ProcessBuilder helps with both these things, allowing easy construction of a list of commands and the ability to merge input and error stream. I recommend trying using it:
Process p = null;
try {
List<String> cmd = new LinkedList<String>();
cmd.add("executable");
cmd.add("-arg1");
cmd.add("value1");
cmd.add("-arg2");
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
p = pb.start();
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (input.ready()) {
String line = input.readLine();
System.out.println("From process: "+line);
}
input.close();
} catch (IOException e) {
this.logMessage("IOException caught: "+e.getMessage());
e.printStackTrace();
}
You need to do this work in a Thread. For example to log the standard output:
Process process = Runtime.getRuntime().exec(command);
LogStreamReader lsr = new LogStreamReader(process.getInputStream());
Thread thread = new Thread(lsr, "LogStreamReader");
thread.start();
public class LogStreamReader implements Runnable {
private BufferedReader reader;
public LoggingStreamReader(InputStream is) {
this.reader = new BufferedReader(new InputStreamReader(is));
}
public void run() {
try {
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then you need a second thread for input handling. And you might want to deal with stderr just like stdout.
I found this code on the net years ago. I cant remember where. It's pretty old so there might be something better out there now.
private void executeCommand(String cmd) {
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
// any error message?
StreamHandler errorGobbler = new StreamHandler(proc.getErrorStream(), "ERR");
// any output?
StreamHandler outputGobbler = new StreamHandler(proc.getInputStream(), "OUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
} catch (Exception e) {
e.printStackTrace();
}
}
And the class:
import java.util.*;
import java.io.*;
public class StreamHandler extends Thread {
InputStream is;
String type;
OutputStream os;
StringBuffer output;
StreamHandler(InputStream is, String type) {
this(is, type, null);
}
StreamHandler(InputStream is, String type, OutputStream redirect) {
this.is = is;
this.type = type;
this.os = redirect;
output = new StringBuffer(100);
}
public void run() {
try {
PrintWriter pw = null;
if (os != null)
pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null) {
if (pw != null)
pw.println(line);
System.out.println(type + ">" + line);
}
if (pw != null)
pw.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
Typically cmd
or terminal
are responsible for setting up standard io for the programs they execute, so I don't think you can just communicate with them via input/output stream. In case of Linux it's actually the shell run inside terminal that executes commands, not terminal itself. Windows probably does some funky things, too.
You can execute commands without actually hard coding cmd.exe into the code.
public static void main(String[] args) {
//cmd = the command youw ill be using
String cmd = "ipconfig";
Runtime r = Runtime.getRuntime();
Process p;
try {
p = r.exec(cmd);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
}
catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
cmd tries to run a command prompt ,
to run the command properly you need the following command line
cmd.exe -c ipconfig.exe
the -c means run the command on the rest of the command line
精彩评论