网站建设客户评价,googleseo排名,wordpress 拒绝连接,企业网站怎么建设方案java程序中要执行linux命令主要依赖2个类#xff1a;Process和Runtime
首先看一下Process类#xff1a;
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程#xff0c;并返回 Process 子类的一个实例#xff0c;
该实例可用来控制进程并获得相关信息。Proces…java程序中要执行linux命令主要依赖2个类Process和Runtime
首先看一下Process类
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程并返回 Process 子类的一个实例
该实例可用来控制进程并获得相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、
检查进程的退出状态以及销毁杀掉进程的方法。
创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作比如本机窗口进程守护进程Microsoft Windows
上的 Win16/DOS 进程或者 shell 脚本。创建的子进程没有自己的终端或控制台。它的所有标准 io即 stdin、stdout 和 stderr
操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。
父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小
如果读写子进程的输出流或输入流迅速出现失败则可能导致子进程阻塞甚至产生死锁。
当没有 Process 对象的更多引用时不是删掉子进程而是继续异步执行子进程。
对于带有 Process 对象的 Java 进程没有必要异步或并发执行由 Process 对象表示的进程。特别需要注意的是
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环境变量字符串数组其中每个环境变量的设置格式为namevalue如果子进程应该继承当前进程的环境则该参数为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_NAMEscott
DB_PWDtiger
DB_SERVERDB_TESTRESULTsqlplus -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和内存的消耗很大。 通过Runtime和Process执行Linux命令 Process是Runtime.exec返回值可以用来对执行过程进行后续操作(获取结果发送命令等待结果)。
注意点 linux命令若需要执行长时间需要调用Process的waitFor方法等待后台任务执行完毕否则其会自动退出 waitFor方法可以设置超时时间防止一直等待 执行需要特定环境变量的命令时可以使用ProcessBuilder的getEnvironment 执行多个命令组合时需要使用{ “/bin/sh”, “-c”, cmd } 需要执行多个命令时可以用连接。 Java调用Linux命令执行
调用方式
Java调用linux命令执行的方式有两种一种是直接调用linux命令一种是将linux命令写到.sh脚本中然后调用脚本执行。
详细说明
直接调用使用java中lang包下面的Runtime类和Process类其中Runtime类中的Runtime.getRuntime().exec(linux command)方法可以直接执行linux命令而Process类可以接收Runtime.getRuntime().exec()类的返回值并提供了waitFor()方法和destroy()方法waitFor()方法的作用在于等待此process执行完成后再执行后面的内容destroy()方法作用在于销毁process。如下程序所示为将fileName路径下的所有文件打包成zip压缩包使用的方法为直接调用。 调用shell脚本直接调用方法存在一些弊端比如复杂命令不好实现、有些命令莫名其妙实现不了等。因此我推荐使用调用shell脚本的方式实现linux命令。具体实现方法为首先将命令写在shell脚本(.sh)中然后在Runtime.getRuntime().exec()中调用“sh path/.sh”其中path为shell脚本的路径。很多情况下我们需要循环调用相同的linux命令来实现我们的功能此时需要向linux命令中传递参数实现案例如下所示: 其中imp.sh中的命令如下所示:
1 name$1
2 su - oracle -c imp user/pwd实例名 filefilepath fully ignorey该语句实现的功能为在root用户下切换到oracle目录并将某个.dmp文件使用imp命令导入oracle数据库然后返回到root用户下将该语句放到for循环中实现了多个.dmp文件导入oracle数据库的功能。其中.dmp文件的文件名是变量在shell命令中以name1代替在linux命令中以1代替在linux命令中以1代替在linux命令中以{name}代指文件名在调用时传入该参数的值linux命令中$1,2…2…2…n是占位变量在使用变量时按顺序使用赋值时按照相应的顺序进行赋值。