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