Java程序执⾏Linux命令
java程序中要执⾏linux命令主要依赖2个类:Process和Runtime
⾸先看⼀下Process类:
ProcessBuilder.start() 和 ⽅法创建⼀个本机进程,并返回 Process ⼦类的⼀个实例,
该实例可⽤来控制进程并获得相关信息。Process 类提供了执⾏从进程输⼊、执⾏输出到进程、等待进程完成、
检查进程的退出状态以及销毁(杀掉)进程的⽅法。
创建进程的⽅法可能⽆法针对某些本机平台上的特定进程很好地⼯作,⽐如,本机窗⼝进程,守护进程,Microsoft Windows
上的 Win16/DOS 进程,或者 shell 脚本。创建的⼦进程没有⾃⼰的终端或控制台。它的所有标准 io(即 stdin、stdout 和 stderr)
操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到⽗进程。
⽗进程使⽤这些流来提供到⼦进程的输⼊和获得从⼦进程的输出。因为有些本机平台仅针对标准输⼊和输出流提供有限的缓冲区⼤⼩,
如果读写⼦进程的输出流或输⼊流迅速出现失败,则可能导致⼦进程阻塞,甚⾄产⽣死锁。
当没有 Process 对象的更多引⽤时,不是删掉⼦进程,⽽是继续异步执⾏⼦进程。
对于带有 Process 对象的 Java 进程,没有必要异步或并发执⾏由 Process 对象表⽰的进程。
特别需要注意的是:
linux重定向1,创建的⼦进程没有⾃⼰的终端控制台,所有标注操作都会通过三个流
(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类实例。
介绍⼏个主要⽅法:
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().exec(new String[]{"sh",
"/home/test/test.sh","select admin from M_ADMIN",
"/home/"});
pro.waitFor();
in = InputStream();
BufferedReader read = new BufferedReader(new InputStreamReader(in));
String result = adLine();
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().exec(cmds);
pro.waitFor();
InputStream in = InputStream();
BufferedReader read = new BufferedReader(new InputStreamReader(in));
String line = null;
while((line = adLine())!=null){
System.out.println(line);
}
}
}
PS:
java虚拟机执⾏这个命令的过程是,⾸先克隆⼀条和当前虚拟机拥有⼀样环境变量的进程,再⽤这个新的进程执⾏外部命令,最后退出这个进程。频繁的创建对CPU和内存的消耗很⼤
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论