背景
java可以通過Runtime來調用其他進程,如cmd命令,shell文件或腳本等。
基本用法
Runtime執行時返回一個Process對象,利用該對象完成腳本執行。下面的例子中,Linux的/home/目錄下有一個刪除指定日期文件的腳本deletefile.sh,Java調用該腳本的方法如下。
/**
* 刪除指定日期的文件
* @param date yyyy-MM-dd格式
*/
private static void setSystemDate(String date){
Process process = null;
String command1 = "/bin/sh /home/deletefile.sh "+date;
System.out.println(command1);
try {
process = Runtime.getRuntime().exec(command1);
//必須等待該進程結束,否則時間設置就無法生效
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}finally{
if(process!=null){
process.destroy();
}
}
}緩衝區滿問題
如果腳本執行過程中產生大量的控制台輸出信息,這種信息會被Shell進程輸出到內存緩衝區中,而上述用法中作為父進程的java進程並沒有處理緩衝區內容,那麼就會出現緩衝區滿,Java進程掛起的情況。
解決辦法是,使用Java線程讀取Shell腳本的輸出信息。
public static List<String> executeShell(String shpath, String var){
//String shpath="/test/test.sh"; // sh 路徑
//String var="201102"; // sh 參數
String shellVar = (var==null)?"":var;
String command1 = "chmod 777 " + shpath; // 為 sh 添加權限
String command2 = "/bin/sh " + shpath + " " + shellVar;
final List<String> strList = new ArrayList<String>();
Process process1 = null;
BufferedReader in = null;
try {
process1 = Runtime.getRuntime().exec(command1); // 執行添加權限的命令
process1.waitFor(); // 如果執行多個命令,必須加上
final Process process2 = Runtime.getRuntime().exec(command2);
//處理InputStream的線程
new Thread() {
@Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(process2.getInputStream()));
String line = null;
try{
while((line = in.readLine()) != null) {
strList.add(line);
}
}catch(IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
//處理ErrorStream的線程
new Thread() {
@Override
public void run(){
BufferedReader err = new BufferedReader(new InputStreamReader(process2.getErrorStream()));
String line = null;
try{
while((line = err.readLine()) != null)
{
strList.add(line);
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
err.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}.start();
process2.waitFor();
} catch (IOException e) {
} catch (InterruptedException e) {
}finally {
if(in != null){
try {
in.close();
} catch (IOException e) {
}
}
if(process1 != null){
process1.destroy();
}
}
return strList;
}線程阻塞問題
如果執行的shell腳本中有等待輸入命令,比如more操作,那麼在使用java進程讀取緩衝區內容的時候,會出現線程阻塞等待的問題。
例如,下面的腳本讀取文件內容。
filePath=/home/software.info
softType=$(more $filePath)
echo $softType上述三行代碼很簡單地輸出了一個文件的內容,而且這個文件很短,只有一行,在Linux下執行沒有問題,但是如果用Java調用executeShell方法執行的話,處理InputStream的線程會出現阻塞等待問題,根源在於腳本中的more命令,它會等待控制台的輸入,從而導致了Java進程的阻塞。
解決辦法就是避免在shell腳本中使用more命令,用cat命令替換即可。
管道命令不執行問題
使用Process執行shell命令時,如果命令中包含管道命令,直接執行會得不到正確結果,解決辦法是使用/bin/sh,將/bin/sh放在待執行的shell命令的前面,可保證管道命令的正確執行。
String command1 = "/bin/sh ifconfig | grep if= | awk '{print $1,$6}'";啟示錄
究竟在Java中調用Shell是不是明智的呢?
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/220752.html
微信掃一掃
支付寶掃一掃