(1) The Process, ProcessBuilder, Runtime
The class Process
provides methods for performing input from the process, performing output to the process, waiting for the process to complete, checking the exit status of the process, and destroying (killing) the process.
In Java, the ProcessBuilder,start() and Runtime.exec() methods create a native process (the Parent Process) and return an instance of a subclass of Process (The Subprocess)
that can be used to control the process (the Parent Process) and obtain information about it.
By default, the created subprocess does not have its own terminal or console. All its standard I/O (i.e. stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), andgetErrorStream(). The parent process uses these streams to feed input to and get output from the subprocess. So, Process.getInputStream() method is used to obtain the output of the native process or parent process. Where desired, subprocess I/O can also be redirected using methods of the ProcessBuilder class, such as the redirect the output of the parent process to a log file
Notice: Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock. Most block problems of invocation shell command is explained by this.
(2) example, a syncAction method to invoke a shell script which would tar a workspace, send the tar to a remote server, then invoke the restore.sh on that server.
public Boolean syncAction() throws Exception {
String succe="ALL_END_SUC";
BufferedReader br=null;
Process p=null;
try {
String cmd="/etc/abc/syncAction.sh";
logger.info("syncCmd:"+cmd);
Runtime r = Runtime.getRuntime();
p = r.exec(cmd);
Thread.sleep(1000);
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String temp= br.readLine();
while(temp!=null){
logger.info("syncCmd:"+temp);
temp= br.readLine();
if(temp.contains(succe)){
logger.info("syncCmd end:"+temp);
return true;
}
}
int rtnCode = -1;
rtnCode = p.waitFor();
logger.info("syncCmd return code=" + rtnCode);
if (rtnCode != 0) {
br = new BufferedReader(new InputStreamReader(
p.getErrorStream()));
String inline;
String errMsg = "";
while ((inline = br.readLine()) != null) {
errMsg += inline;
errMsg += System.getProperty("line.separator");
}
logger.error("error when exec SyncOne, error message is "+ errMsg);
return false;
}
return true;
} catch (Exception e) {
logger.error("SyncAction:",e);
return false;
}finally{
if(p!=null){
p.destroy();
}
if(br!=null){
try{
br.close();
}catch(Exception e){
}
}
}
}
(3) the problems
There are two parts in above method to finish the invocation, one is to catch the SUC single, the other is to invoke p.waitFor(); the former one is preference, because the latter one is more complex.
No matter whether it needs to print the output of Parent Process, the while() loop is necessary, Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock. In java, Null is used to represent the end of the stream.
And even though this loop is used, the block is still encountered, the further way is to reduce the output message of the Stream. Especially, some linux command which have the V argument meaning verbose and leading to a mass of output, should always be thought highly of. For example, the tar -zcvf , tar -zxvf, rm -vrf, and so on.