中易网

java程序里调用linux命令

答案:5  悬赏:80  
解决时间 2021-03-15 18:52
我们的java程序部署在linux(suse)环境下,部署好之后客户可以访问页面。有时候我们的系统升级,需要更换正在使用的class文件(或者其他配置文件)。但此时这些要被更新的文件正在被客户占用,我尝试过用 File类里的delete()方法,如果文件被占用,此方法返回false,也就是说删除失败。
我在想,java里能不能通过调用linux命令,来强制删除正在使用的文件呢?(注:删除这些文件对系统不会造成影响,只是我们后台用来更新版本用的) 。我知道linux里有个rm -rf可以强制删除。具体该怎么调用呢?另外,如果调用了rm -rm ,一定能保证文件被成功删除吗?
最佳答案
1.Java调用shell
Java语言以其跨平台性和简易性而著称,在Java里面的lang包里(java.lang.Runtime)提供了一个允许Java程序与该程序所运
行的环境交互的接口,这就是Runtime类,在Runtime类里提供了获取当前运行环境的接口。
其中的exec函数返回一个执行shell命令的子进程。exec函数的具体实现形式有以下几种:
public Process exec(String command) throws IOException
public Process exec(String command,String[] envp) throws
IOException
public Process exec(String command,String[] envp,File dir) throws
IOException
public Process exec(String[] cmdarray) throws IOException
public Process exec(String[] cmdarray, String[] envp) throws
IOException
public Process exec(String[] cmdarray, String[] envp,File dir)
throws IOException

我们在这里主要用到的是第一个和第四个函数,具体方法很简单,就是在exec函数中传递一个代表命令的字符串。exec函数返回的是一个Process类
型的类的实例。Process类主要用来控制进程,获取进程信息等作用。(具体信息及其用法请参看Java doc)。
1)执行简单的命令的方法:
代码如下:




上面的代码首先是声明了一个代表命令的字符串commands,它代表了ls -l
这个命令。之后我们用Runtime.getRuntime().exec(commands)来生成一个子进程来执行这个命令,如果这句话运行成功,则
命令 ls -l 运行成功(由于没有让它显示,不会显示ls -l
的结果)。后面的流操作则是获取进程的流信息,并把它们一行行输出到屏幕。2)执行带有参数的命令(尤其是参数需要用引号的)时则需要用String的数组来表示整个命令,而且要用转义符把引号的特殊含义去除,例如我们要执行
find / -name "*mysql*" -print 时,用如下代码



Java 可以通过 Runtime 调用Linux命令,形式如下:
Runtime.getRuntime().exec(command)
但是这样执行时没有任何输出,因为调用 Runtime.exec 方法将产生一个本地的进程,并返回一个Process子类的实例(注意:Runtime.getRuntime().exec(command)返回的是一个Process类的实例)该实例可用于控制进程或取得进程的相关信息。
由于调用 Runtime.exec 方法所创建的子进程没有自己的终端或控制台,因此该子进程的标准IO(如stdin,stdou,stderr)都通过 Process.getOutputStream(),Process.getInputStream(), Process.getErrorStream() 方法重定向给它的父进程了。
用户需要用这些stream来向子进程输入数据或获取子进程的输出,下面的代码可以取到 linux 命令的执行结果:

全部回答
以下方法支持Linux和windows两个系统的命令行调用。还用到了apache的lang工具包commons-lang3-3.1.jar来判断操作系统类型、也用到了和log4j-1.2.16.jar来打印日志。至于rm -rf 是否能成功删除文件,可以手动去调用命令行试试。 private String callCmd(String cmd) throws InterruptedException, UnHandledOSException, ExecuteException { if(SystemUtils.IS_OS_LINUX){ try { // 使用Runtime来执行command,生成Process对象 Process process = Runtime.getRuntime().exec( new String[] { "/bin/sh", "-c", cmd }); int exitCode = process.waitFor(); // 取得命令结果的输出流 InputStream is = process.getInputStream(); // 用一个读输出流类去读 InputStreamReader isr = new InputStreamReader(is); // 用缓冲器读行 BufferedReader br = new BufferedReader(isr); String line = null; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { System.out.println(line); sb.append(line); } is.close(); isr.close(); br.close(); return sb.toString(); } catch (java.lang.NullPointerException e) { System.err.println("NullPointerException " + e.getMessage()); logger.error(cmd); } catch (java.io.IOException e) { System.err.println("IOException " + e.getMessage()); } throw new ExecuteException(cmd + "执行出错!"); } if(SystemUtils.IS_OS_WINDOWS){ Process process; try { //process = new ProcessBuilder(cmd).start(); String[] param_array = cmd.split("[\\s]+"); ProcessBuilder pb = new ProcessBuilder(param_array); process = pb.start(); int exitCode = process.waitFor(); InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { System.out.println(line); sb.append(line); } is.close(); isr.close(); br.close(); return sb.toString(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } throw new ExecuteException(cmd + "执行出错!"); } throw new UnHandledOSException("不支持本操作系统"); }  以下是测试代码 public class ExecuteCmdCommand { static Logger logger = Logger.getLogger(ExecuteCmdCommand.class.getName()); public static void main(String[] args) throws InterruptedException, UnHandledOSException, ExecuteException { // TODO Auto-generated method stub ExecuteCmdCommand executeCmdCommand = new ExecuteCmdCommand(); if(SystemUtils.IS_OS_LINUX){ executeCmdCommand.callCmd("ls -al"); }else if(SystemUtils.IS_OS_WINDOWS){ executeCmdCommand.callCmd("dir"); }else{ System.out.println("不支持的OS"); } } public class ExecuteException extends Exception {     public ExecuteException() {         super();         // TODO Auto-generated constructor stub     }     public ExecuteException(String arg0) {         super(arg0);         // TODO Auto-generated constructor stub     } } public class UnHandledOSException extends Exception { public UnHandledOSException() { super(); // TODO Auto-generated constructor stub } public UnHandledOSException(String arg0) { super(arg0); // TODO Auto-generated constructor stub } } private String callCmd(String cmd) throws InterruptedException, UnHandledOSException, ExecuteException {         if(SystemUtils.IS_OS_LINUX){             try {                 // 使用Runtime来执行command,生成Process对象                 Process process = Runtime.getRuntime().exec(                         new String[] { "/bin/sh", "-c", cmd });                 int exitCode = process.waitFor();                 // 取得命令结果的输出流                 InputStream is = process.getInputStream();                 // 用一个读输出流类去读                 InputStreamReader isr = new InputStreamReader(is);                 // 用缓冲器读行                 BufferedReader br = new BufferedReader(isr);                 String line = null;                 StringBuilder sb = new StringBuilder();                 while ((line = br.readLine()) != null) {                     System.out.println(line);                     sb.append(line);                 }                 is.close();                 isr.close();                 br.close();                 return sb.toString();             } catch (java.lang.NullPointerException e) {                 System.err.println("NullPointerException " + e.getMessage());                 logger.error(cmd);             } catch (java.io.IOException e) {                 System.err.println("IOException " + e.getMessage());             }             throw new ExecuteException(cmd + "执行出错!");         }         if(SystemUtils.IS_OS_WINDOWS){             Process process;             try {                 //process = new ProcessBuilder(cmd).start();                 String[] param_array = cmd.split("[\\s]+");                 ProcessBuilder pb = new ProcessBuilder(param_array);                 process = pb.start();                                  int exitCode = process.waitFor();                 InputStream is = process.getInputStream();                 InputStreamReader isr = new InputStreamReader(is);                 BufferedReader br = new BufferedReader(isr);                 String line;                 StringBuilder sb = new StringBuilder();                 while ((line = br.readLine()) != null) {                     System.out.println(line);                     sb.append(line);                 }                 is.close();                 isr.close();                 br.close();                 return sb.toString();             } catch (IOException e) {                 // TODO Auto-generated catch block                 e.printStackTrace();             }             throw new ExecuteException(cmd + "执行出错!");         }         throw new UnHandledOSException("不支持本操作系统");     } }
Java 可以通过 Runtime 调用Linux命令,形式如下: 1. Runtime.getRuntime().exec(command) 但是这样执行时没有任何输出,因为调用 Runtime.exec 方法将产生一个本地的进程,并返回一个Process子类的实例(注意:Runtime.getRuntime().exec(command)返回的是一个Process类的实例)该实例可用于控制进程或取得进程的相关信息。 2. 由于调用 Runtime.exec 方法所创建的子进程没有自己的终端或控制台,因此该子进程的标准IO(如stdin,stdou,stderr)都通过 Process.getOutputStream(),Process.getInputStream(), Process.getErrorStream() 方法重定向给它的父进程了。 3. 用户需要用这些stream来向子进程输入数据或获取子进程的输出,下面的代码可以取到 linux 命令的执行结果: try { String[] cmd = new String[]{”/bin/sh”, “-c”, ” ls “}; Process ps = Runtime.getRuntime().exec(cmd); BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); StringBuffer sb = new StringBuffer(); String line; while ((line = br.readLine()) != null) { sb.append(line).append(”\n”); } String result = sb.toString(); System.out.println(result); } catch (Exception e) { e.printStackTrace(); }
做到这,主要依赖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:环境变量字符串数组,其中每个环境变量的设置格式为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和内存的消耗很大。
做到这,主要依赖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:环境变量字符串数组,其中每个环境变量的设置格式为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和内存的消耗很大。
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
想一个关于代理零食的昵称,谢谢你们
恒泰海产文化路店地址有知道的么?有点事想过
套读什么意思
柯南的QQ账号是多少
河北师范大学新校区 建行卡补办
韩记粥铺快餐地址在哪,我要去那里办事
谁在农民的命根子上动了手脚?谁来保护农民的
松脂油的用途是干什么的啊
提问话说四川猜一字
肌肉拉伸最好是多长时间?锻炼完吃鸡蛋(带蛋
6名员工集体罢工,写辞职报告好还是不写好?
无锡交通产业集团工资待遇昨样
民珍茶行怎么去啊,有知道地址的么
本人赠送5位QQ号码,送QQ
车衣裳靓车会地址在哪,我要去那里办事
推荐资讯
鄢家垭大桥/老白路(路口)地址有知道的么?有
寒猿是什么意思
平铁路在什么地方啊,我要过去处理事情
一个三角形,已知角1的度数是角2的2倍,角3的
"激励"是什么意思?
西工大学位考试通过率是怎么样的
福利彩票2元1注和10元1注奖金有什么分别
谁有好听的越南歌曲
德克士牡丹餐厅我想知道这个在什么地方
如何能抓住水瓶座女孩的心
如何让同一帐号的iPhone和iPad不同步数据
灿烂人生佳恩是在第几集发现老公出轨
手机登qq时,显示手机磁盘不足,清理后重新登
刺客的套装怎么选啊?