生活随笔
收集整理的這篇文章主要介紹了
Java程序执行Linux命令
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
java程序中要執(zhí)行l(wèi)inux命令主要依賴2個(gè)類:Process和Runtime
首先看一下Process類:
[plain] view plaincopyprint?
ProcessBuilder.start()?和?Runtime.exec?方法創(chuàng)建一個(gè)本機(jī)進(jìn)程,并返回?Process?子類的一個(gè)實(shí)例,?? 該實(shí)例可用來控制進(jìn)程并獲得相關(guān)信息。Process?類提供了執(zhí)行從進(jìn)程輸入、執(zhí)行輸出到進(jìn)程、等待進(jìn)程完成、?? 檢查進(jìn)程的退出狀態(tài)以及銷毀(殺掉)進(jìn)程的方法。?? 創(chuàng)建進(jìn)程的方法可能無法針對(duì)某些本機(jī)平臺(tái)上的特定進(jìn)程很好地工作,比如,本機(jī)窗口進(jìn)程,守護(hù)進(jìn)程,Microsoft?Windows?? 上的?Win16/DOS?進(jìn)程,或者?shell?腳本。創(chuàng)建的子進(jìn)程沒有自己的終端或控制臺(tái)。它的所有標(biāo)準(zhǔn)?io(即?stdin、stdout?和?stderr)?? 操作都將通過三個(gè)流?(getOutputStream()、getInputStream()?和?getErrorStream())?重定向到父進(jìn)程。?? 父進(jìn)程使用這些流來提供到子進(jìn)程的輸入和獲得從子進(jìn)程的輸出。因?yàn)橛行┍緳C(jī)平臺(tái)僅針對(duì)標(biāo)準(zhǔn)輸入和輸出流提供有限的緩沖區(qū)大小,?? 如果讀寫子進(jìn)程的輸出流或輸入流迅速出現(xiàn)失敗,則可能導(dǎo)致子進(jìn)程阻塞,甚至產(chǎn)生死鎖。?? 當(dāng)沒有?Process?對(duì)象的更多引用時(shí),不是刪掉子進(jìn)程,而是繼續(xù)異步執(zhí)行子進(jìn)程。?? 對(duì)于帶有?Process?對(duì)象的?Java?進(jìn)程,沒有必要異步或并發(fā)執(zhí)行由?Process?對(duì)象表示的進(jìn)程。??
ProcessBuilder.start() 和 Runtime.exec 方法創(chuàng)建一個(gè)本機(jī)進(jìn)程,并返回 Process 子類的一個(gè)實(shí)例,
該實(shí)例可用來控制進(jìn)程并獲得相關(guān)信息。Process 類提供了執(zhí)行從進(jìn)程輸入、執(zhí)行輸出到進(jìn)程、等待進(jìn)程完成、
檢查進(jìn)程的退出狀態(tài)以及銷毀(殺掉)進(jìn)程的方法。
創(chuàng)建進(jìn)程的方法可能無法針對(duì)某些本機(jī)平臺(tái)上的特定進(jìn)程很好地工作,比如,本機(jī)窗口進(jìn)程,守護(hù)進(jìn)程,Microsoft Windows
上的 Win16/DOS 進(jìn)程,或者 shell 腳本。創(chuàng)建的子進(jìn)程沒有自己的終端或控制臺(tái)。它的所有標(biāo)準(zhǔn) io(即 stdin、stdout 和 stderr)
操作都將通過三個(gè)流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父進(jìn)程。
父進(jìn)程使用這些流來提供到子進(jìn)程的輸入和獲得從子進(jìn)程的輸出。因?yàn)橛行┍緳C(jī)平臺(tái)僅針對(duì)標(biāo)準(zhǔn)輸入和輸出流提供有限的緩沖區(qū)大小,
如果讀寫子進(jìn)程的輸出流或輸入流迅速出現(xiàn)失敗,則可能導(dǎo)致子進(jìn)程阻塞,甚至產(chǎn)生死鎖。
當(dāng)沒有 Process 對(duì)象的更多引用時(shí),不是刪掉子進(jìn)程,而是繼續(xù)異步執(zhí)行子進(jìn)程。
對(duì)于帶有 Process 對(duì)象的 Java 進(jìn)程,沒有必要異步或并發(fā)執(zhí)行由 Process 對(duì)象表示的進(jìn)程。
特別需要注意的是:
1,創(chuàng)建的子進(jìn)程沒有自己的終端控制臺(tái) ,所有標(biāo)注操作都會(huì)通過三個(gè)流
(getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父進(jìn)程(父進(jìn)程可通過這些流判斷子進(jìn)程的執(zhí)行情況 )
2,因?yàn)?span style="color:#ff00">有些本機(jī)平臺(tái)僅針對(duì)標(biāo)準(zhǔn)輸入和輸出流提供有限的緩沖區(qū)大小,如果讀寫子進(jìn)程的輸出流或輸入流迅速出現(xiàn)失敗,
則可能導(dǎo)致子進(jìn)程阻塞,甚至產(chǎn)生死鎖
[plain] view plaincopyprint?
abstract??void?destroy()??? ??????????殺掉子進(jìn)程。??? abstract??int?exitValue()??? ??????????返回子進(jìn)程的出口值。根據(jù)慣例,值0表示正常終止。??? abstract??InputStream?getErrorStream()??? ??????????獲取子進(jìn)程的錯(cuò)誤流。??? abstract??InputStream?getInputStream()??? ??????????獲取子進(jìn)程的輸入流。??? abstract??OutputStream?getOutputStream()??? ??????????獲取子進(jìn)程的輸出流。??? abstract??int?waitFor()??? ??????????導(dǎo)致當(dāng)前線程等待,如有必要,一直要等到由該?Process?對(duì)象表示的進(jìn)程已經(jīng)終止。?? ?????如果已終止該子進(jìn)程,此方法立即返回。如果沒有終止該子進(jìn)程,調(diào)用的線程將被阻塞,直到退出子進(jìn)程。??
abstract void destroy() 殺掉子進(jìn)程。
abstract int exitValue() 返回子進(jìn)程的出口值。根據(jù)慣例,值0表示正常終止。
abstract InputStream getErrorStream() 獲取子進(jìn)程的錯(cuò)誤流。
abstract InputStream getInputStream() 獲取子進(jìn)程的輸入流。
abstract OutputStream getOutputStream() 獲取子進(jìn)程的輸出流。
abstract int waitFor() 導(dǎo)致當(dāng)前線程等待,如有必要,一直要等到由該 Process 對(duì)象表示的進(jìn)程已經(jīng)終止。如果已終止該子進(jìn)程,此方法立即返回。如果沒有終止該子進(jìn)程,調(diào)用的線程將被阻塞,直到退出子進(jìn)程。
特別需要注意:如果子進(jìn)程中的輸入流,輸出流或錯(cuò)誤流中的內(nèi)容比較多,最好使用緩存 (注意上面的情況2)
再來看一下Runtime類:
[plain] view plaincopyprint?
每個(gè)Java應(yīng)用程序都有一個(gè)Runtime類實(shí)例,使應(yīng)用程序能夠與其運(yùn)行的環(huán)境相連接。可以通過getRuntime方法獲取當(dāng)前運(yùn)行時(shí)環(huán)境。??? 應(yīng)用程序不能創(chuàng)建自己的Runtime類實(shí)例。???
每個(gè)Java應(yīng)用程序都有一個(gè)Runtime類實(shí)例,使應(yīng)用程序能夠與其運(yùn)行的環(huán)境相連接。可以通過getRuntime方法獲取當(dāng)前運(yùn)行時(shí)環(huán)境。
應(yīng)用程序不能創(chuàng)建自己的Runtime類實(shí)例。
介紹幾個(gè)主要方法:
[plain] view plaincopyprint?
Process?exec(String?command)??? ?????????在單獨(dú)的進(jìn)程中執(zhí)行指定的字符串命令。?? Process?exec(String?command,?String[]?envp)??? ?????????在指定環(huán)境的單獨(dú)進(jìn)程中執(zhí)行指定的字符串命令。?? Process?exec(String?command,?String[]?envp,?File?dir)??? ?????????在有指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的字符串命令。?? Process?exec(String[]?cmdarray)??? ?????????在單獨(dú)的進(jìn)程中執(zhí)行指定命令和變量。??? Process?exec(String[]?cmdarray,?String[]?envp)??? ?????????在指定環(huán)境的獨(dú)立進(jìn)程中執(zhí)行指定命令和變量。??? Process?exec(String[]?cmdarray,?String[]?envp,?File?dir)??? ?????????在指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的命令和變量。???
Process exec(String command) 在單獨(dú)的進(jìn)程中執(zhí)行指定的字符串命令。Process exec(String command, String[] envp) 在指定環(huán)境的單獨(dú)進(jìn)程中執(zhí)行指定的字符串命令。Process exec(String command, String[] envp, File dir) 在有指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的字符串命令。Process exec(String[] cmdarray) 在單獨(dú)的進(jìn)程中執(zhí)行指定命令和變量。 Process exec(String[] cmdarray, String[] envp) 在指定環(huán)境的獨(dú)立進(jìn)程中執(zhí)行指定命令和變量。 Process exec(String[] cmdarray, String[] envp, File dir) 在指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的命令和變量。
command:一條指定的系統(tǒng)命令。
envp:環(huán)境變量字符串?dāng)?shù)組,其中每個(gè)環(huán)境變量的設(shè)置格式為name=value;如果子進(jìn)程應(yīng)該繼承當(dāng)前進(jìn)程的環(huán)境,則該參數(shù)為null。
dir:子進(jìn)程的工作目錄;如果子進(jìn)程應(yīng)該繼承當(dāng)前進(jìn)程的工作目錄,則該參數(shù)為null。
cmdarray:包含所調(diào)用命令及其參數(shù)的數(shù)組。
以下為示例(要打成可執(zhí)行jar包扔到linux下執(zhí)行):
[java] view plaincopyprint?
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();?? ????????}?? ????}?? }??
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)這個(gè)方法
?/home/test/test.sh腳本如下:
[plain] view plaincopyprint?
#!/bin/sh?? ?? #查詢sql?? SQL=$1?? #查詢結(jié)果保存文件?? RESULT_FILE=$2?? #數(shù)據(jù)庫(kù)連接?? 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;??
#!/bin/sh#查詢sql
SQL=$1
#查詢結(jié)果保存文件
RESULT_FILE=$2
#數(shù)據(jù)庫(kù)連接
DB_NAME=scott
DB_PWD=tiger
DB_SERVER=DB_TESTRESULT=`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;
特別需要注意的是,當(dāng)需要執(zhí)行的linux命令帶有管道符時(shí)(例如:ps -ef|grep java),用上面的方法是不行的,解決方式是將需要執(zhí)行的命令作為參數(shù)傳給shell
[java] view plaincopyprint?
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);?? ????????}?? ????}?? }??
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()這種調(diào)用方式在java虛擬機(jī)中是十分消耗資源的,即使命令可以很快的執(zhí)行完畢,頻繁的調(diào)用時(shí)創(chuàng)建進(jìn)程消耗十分客觀。
java虛擬機(jī)執(zhí)行這個(gè)命令的過程是,首先克隆 一條和當(dāng)前虛擬機(jī)擁有一樣環(huán)境變量的進(jìn)程,再用這個(gè)新的進(jìn)程執(zhí)行外部命令,最后退出這個(gè)進(jìn)程。頻繁的創(chuàng)建對(duì)CPU和內(nèi)存的消耗很大
總結(jié)
以上是生活随笔 為你收集整理的Java程序执行Linux命令 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。