Java程序中要執行linux命令主要依賴2個類:Process和Runtimejava
首先看一下Process類:linux
- ProcessBuilder.start() 和 Runtime.exec 方法建立一個本機進程,並返回 Process 子類的一個實例,
- 該實例可用來控制進程並得到相關信息。Process 類提供了執行從進程輸入、執行輸出到進程、等待進程完成、
- 檢查進程的退出狀態以及銷燬(殺掉)進程的方法。
- 建立進程的方法可能沒法針對某些本機平臺上的特定進程很好地工做,好比,本機窗口進程,守護進程,Microsoft Windows
- 上的 Win16/DOS 進程,或者 shell 腳本。建立的子進程沒有本身的終端或控制檯。它的全部標準 io(即 stdin、stdout 和 stderr)
- 操做都將經過三個流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父進程。
- 父進程使用這些流來提供到子進程的輸入和得到從子進程的輸出。由於有些本機平臺僅針對標準輸入和輸出流提供有限的緩衝區大小,
- 若是讀寫子進程的輸出流或輸入流迅速出現失敗,則可能致使子進程阻塞,甚至產生死鎖。
- 當沒有 Process 對象的更多引用時,不是刪掉子進程,而是繼續異步執行子進程。
- 對於帶有 Process 對象的 Java 進程,沒有必要異步或併發執行由 Process 對象表示的進程。
特別須要注意的是:sql
1,建立的子進程沒有本身的終端控制檯,全部標註操做都會經過三個流shell
(getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父進程(父進程可經過這些流判斷子進程的執行狀況)數據庫
2,由於有些本機平臺僅針對標準輸入和輸出流提供有限的緩衝區大小,若是讀寫子進程的輸出流或輸入流迅速出現失敗,數組
則可能致使子進程阻塞,甚至產生死鎖緩存
- abstract void destroy()
- 殺掉子進程。
- abstract int exitValue()
- 返回子進程的出口值。根據慣例,值0表示正常終止。
- abstract InputStream getErrorStream()
- 獲取子進程的錯誤流。
- abstract InputStream getInputStream()
- 獲取子進程的輸入流。
- abstract OutputStream getOutputStream()
- 獲取子進程的輸出流。
- abstract int waitFor()
- 致使當前線程等待,若有必要,一直要等到由該 Process 對象表示的進程已經終止。
- 若是已終止該子進程,此方法當即返回。若是沒有終止該子進程,調用的線程將被阻塞,直到退出子進程。
特別須要注意:若是子進程中的輸入流,輸出流或錯誤流中的內容比較多,最好使用緩存(注意上面的狀況2)併發
再來看一下Runtime類:異步
- 每一個Java應用程序都有一個Runtime類實例,使應用程序可以與其運行的環境相鏈接。能夠經過getRuntime方法獲取當前運行時環境。
- 應用程序不能建立本身的Runtime類實例。
介紹幾個主要方法:ui
- Process exec(String command)
- 在單獨的進程中執行指定的字符串命令。
- Process exec(String command, String[] envp)
- 在指定環境的單獨進程中執行指定的字符串命令。
- Process exec(String command, String[] envp, File dir)
- 在有指定環境和工做目錄的獨立進程中執行指定的字符串命令。
- Process exec(String[] cmdarray)
- 在單獨的進程中執行指定命令和變量。
- Process exec(String[] cmdarray, String[] envp)
- 在指定環境的獨立進程中執行指定命令和變量。
- Process exec(String[] cmdarray, String[] envp, File dir)
- 在指定環境和工做目錄的獨立進程中執行指定的命令和變量。
command:一條指定的系統命令。
envp:環境變量字符串數組,其中每一個環境變量的設置格式爲name=value;若是子進程應該繼承當前進程的環境,則該參數爲null。
dir:子進程的工做目錄;若是子進程應該繼承當前進程的工做目錄,則該參數爲null。
cmdarray:包含所調用命令及其參數的數組。
如下爲示例(要打成可執行jar包扔到linux下執行):
- public class test {
- public static void main(String[] args){
- InputStream in = null;
- try {
- Process pro = Runtime.getRuntime().exec(new String[]{"sh",
- "/home/test/test.sh","select admin from M_ADMIN",
- "/home/test/result.txt"});
- pro.waitFor();
- in = pro.getInputStream();
- BufferedReader read = new BufferedReader(new InputStreamReader(in));
- String result = read.readLine();
- System.out.println("INFO:"+result);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
在這用的是Process exec(String[] cmdarray)這個方法
/home/test/test.sh腳本以下:
- #!/bin/sh
-
- #查詢sql
- SQL=$1
- #查詢結果保存文件
- RESULT_FILE=$2
- #數據庫鏈接
- DB_NAME=scott
- DB_PWD=tiger
- DB_SERVER=DB_TEST
-
- RESULT=`sqlplus -S ${DB_NAME}/${DB_PWD}@${DB_SERVER}<< !
- set heading off
- set echo off
- set pages 0
- set feed off
- set linesize 3000
- ${SQL}
- /
- commit
- /
- !`
-
- echo "${RESULT}" >> ${RESULT_FILE}
- echo 0;
特別須要注意的是,當須要執行的linux命令帶有管道符時(例如:ps -ef|grep java),用上面的方法是不行的,解決方式是將須要執行的命令做爲參數傳給shell
- public class Test {
- public static void main(String[] args) throws Exception{
- String[] cmds = {"/bin/sh","-c","ps -ef|grep java"};
- Process pro = Runtime.getRuntime().exec(cmds);
- pro.waitFor();
- InputStream in = pro.getInputStream();
- BufferedReader read = new BufferedReader(new InputStreamReader(in));
- String line = null;
- while((line = read.readLine())!=null){
- System.out.println(line);
- }
- }
- }
PS:
Runtime.getRuntime().exec()這種調用方式在java虛擬機中是十分消耗資源的,即便命令能夠很快的執行完畢,頻繁的調用時建立進程消耗十分客觀。
java虛擬機執行這個命令的過程是,首先克隆一條和當前虛擬機擁有同樣環境變量的進程,再用這個新的進程執行外部命令,最後退出這個進程。頻繁的建立對CPU和內存的消耗很大
原文地址:http://blog.csdn.net/a19881029/article/details/8063758