
以下方法支持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()
/*process=Runtime.getRuntime().exec(cmd)*/
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("不支持本 *** 作系统")
}
其实不难,给你思路如下:第一,你需要在远程Linux主机上面装好一个接收端程序,这个程序可以是java写的,也可以是C语言写的,都无所谓,因为网络接口是一样的,都是socket。
如果你要用java写,那需要在Linux上面把jdk装上,推荐你用C写,更容易 *** 作linux执行cmd命令.
假设从主机A,检查主机B上的进程,
需要在主机B上建立检查用户,例如叫x,
并设置通过public key认证登录SSH,不会可以google搜一下,
然后,在A机器上执行:
ssh x@B ~/command.sh >result.txt
command.sh就是B机器上放置在x目录下的脚本。
输出结果应该是写到了result.txt
或者另一种写法
result=`ssh x@B ~/command.sh`
结果直接保存到result变量中了。
暂时没有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:环境变量字符串数组,其中每个环境变量的设置格式为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和内存的消耗很大。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)