1.使用Runtime.getRuntime().exec()方法
sshUtil.java
package com.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
public class SSHUtil {
private String host; // ip
private String username;
private String password;
/**
* @param host(ip)
* @param username(用户名)
* @param password(密码)
*/
public SSHUtil(String host, String username, String password) {
this.host = host;
this.username = username;
this.password = password;
}
private Connection conn = null;
/**
* 连接
*/
private boolean connect() {
conn = new Connection(host);
try {
conn.connect();
if (conn.authenticateWithPassword(username, password)) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 执行命令
*/
public String execute(String command) {
if (command == null || "null".equals(command)) {
return "传入命令为空!!!";
}
if (!connect()) {
return "连接服务器失败!!!";
}
Session session = null;
try {
session = conn.openSession();
session.execCommand(command);
InputStream stdout = new StreamGobbler(session.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
StringBuffer sb = new StringBuffer();
// ExitCode正常为0
// 1:报错、2:误用命令、126:命令不得执行、127:没找到命令、130:ctrl+c结束、255:返回码超出范围
sb.append("ExitCode: " + session.getExitStatus() + "\n");
while (true) {
String line = br.readLine();
if (line == null)
break;
sb.append(line + "\n");
}
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
return "error";
} finally {
if (conn != null) {
conn.close();
}
if (session != null) {
session.close();
}
}
}
}
SSHMain.java
package com.demo;
public class SSHMain {
public static void main(String[] args) {
SSHUtil sshUtil=new SSHUtil("1.117.23.51","root","xxxx");
String c1="cd /";
String e1 = sshUtil.execute(c1);
System.out.println(e1);
String c2="pwd";
String e2 = sshUtil.execute(c2);
System.out.println(e2);
}
}
执行结果:
命令执行之Runtime.getRuntime().exec()
在java中,RunTime.getRuntime().exec()实现了调用服务器命令脚本来执行功能需要。
用法:
public Process exec(String command)-----在单独的进程中执行指定的字符串命令。
public Process exec(String [] cmdArray)---在单独的进程中执行指定命令和变量
public Process exec(String command, String [] envp)----在指定环境的独立进程中执行指定命令和变量
public Process exec(String [] cmdArray, String [] envp)----在指定环境的独立进程中执行指定的命令和变量
public Process exec(String command,String[] envp,File dir)----在有指定环境和工作目录的独立进程中执行指定的字符串命令
public Process exec(String[] cmdarray,String[] envp,File dir)----在指定环境和工作目录的独立进程中执行指定的命令和变量
举例:
1,打开windows下记事本
RunTime.getRuntime().exec(String command);
在windows下相当于直接调用 /开始/搜索程序和文件 的指令,比如
Runtime.getRuntime().exec("notepad.exe"); -------打开windows下记事本。
2,public Process exec(String [] cmdArray);
Linux下:
Runtime.getRuntime().exec(new String[]{"/bin/sh","-c", cmds});
Windows下:
Runtime.getRuntime().exec(new String[]{ "cmd", "/c", cmds});
实例:
String command = "find " + source.getRoute() + " -name '" +source.getName();
Process process = Runtime.getRuntime().exec(new String[] {"/bin/sh","-c",command});
补充:#!/bin/bash和#!/bin/sh的区别
#! 是个指示路径的表示符,/bin/bash和/bin/sh指定了脚本解析器的程序路径
bash是sh的完整版,bash完全兼容sh命令,反之不行
OPTIONS:
-c string 该选项表明string中包含了一条命令.如 bash -c ls ~
-i 使Bash以交互式方式运行
-r 使Bash以受限方式运行
–login 使Bash以登录Shell方式运行
–posix 使Bash遵循POSIX标准
–verbose 使Bash显示所有其读入的输入行
–help 打印Bash的使用信息
–version 打印版本信息
深入:
Process的几种用法:
1.destroy();杀掉子进程
2.exitValue();返回子进程的出口值,值0表示正常终止
3.getErrorStream();获取自己进程错误输出的输入流
4.getInputStream();这里是获取子进程输出的输入流
5.getOutputStream();获取子进程输入的输出流
6.waitFor();导致当前线程等待,如有必要,一直要等到由该Process对象表示的进程已经终止,如果已终止该子进程,此方法立即返回,如果没有终止该子进程,调用的线程将被阻塞,直到推出子进程,根据惯例,0表示正常终止
这里可能解释的不够清楚,首先子进程是指我们使用exec
方法执行的进程,以getInputStream()
方法为例,子进程的输出对于我们程序的进程是输入,所有相对java程序而言是输入流。
注意:在java中,调用runtime线程执行脚本是非常消耗资源的,所以切忌不要频繁使用!
在调用runtime去执行脚本的时候,其实就是JVM开了一个子线程去调用JVM所在系统的命令,其中开了三个通道: 输入流、输出流、错误流,其中输出流就是子线程走调用的通道。
大家都知道,waitFor是等待子线程执行命令结束后才执行, 但是在runtime中,打开程序的命令如果不关闭,就不算子线程结束。比如以下代码。
代码:
private static Process p = null;
p = Runtime.getRuntime().exec(“notepad.exe”);
p.waitFor();
System.out.println("--------------------------------------------我被执行了");
以上代码中,打开windows中记事本。如果我们不手动关闭记事本,那么输出语句就不会被执行,这点是需要理解的。
process的阻塞:
在runtime执行大点的命令中,输入流和错误流会不断有流进入存储在JVM的缓冲区中,如果缓冲区的流不被读取被填满时,就会造成runtime的阻塞。所以在进行比如:大文件复制等的操作时,我们还需要不断的去读取JVM中的缓冲区的流,来防止Runtime的死锁阻塞。
Java Runtime.exec()的使用
windows下调用程序
Process proc =Runtime.getRuntime().exec("exefile");
Linux下调用程序
Process proc =Runtime.getRuntime().exec("./exefile");
windows下调用程序系统命令
String [] cmd={"cmd","/C","copy exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);
Linux下调用系统命令就要改成下面的格式
String [] cmd={"/bin/sh","-c","ln -s exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);
windows下调用系统命令并弹出命令行窗口
String [] cmd={"cmd","/C","start copy exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);
Linux下调用系统命令并弹出终端窗口
String [] cmd={"/bin/sh","-c","xterm -e ln -s exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);
还有要设置调用程序的工作目录就要
Process proc =Runtime.getRuntime().exec("exeflie",null, new File("workpath"));
最好的执行命令的方法就是写个bat文件或者shell脚本,然后调用,那样修改和实现就简单多了
Java现在执行外部命令,主要的方式,还是通过调用平台的shell去完成,windows下就用cmd,Linux或者unix下面就用shell,下面演示对一个bat文件的调用,并把结果回显到控制台上。
读取bat配置文件
1.准备bat文件
2,编写代码
package com.ssh;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class JavaExeBat {
public static void main(String[] args) {
Process process;
String cmd="D:\\Demo03\\test.bat";
try {
//执行命令
process = Runtime.getRuntime().exec(cmd);
//取得命令结果的输出流
InputStream inputStream = process.getInputStream();
//用一个读输出流类去读
InputStreamReader isr = new InputStreamReader(inputStream, Charset.forName("GBK"));
//用缓冲器读行
BufferedReader br = new BufferedReader(isr);
String line=null;
//知道读完为止
while ((line=br.readLine())!=null){
System.out.println(line);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
3.执行结果
使用cmd /C
package com.ssh;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class JavaExeBat {
public static void main(String[] args) {
Process process;
//String cmd="D:\\Demo03\\test.bat";
//String cmd="dir ";
//String [] cmd={"cmd","/C","start copy exe1.txt exe4.txt"};
String [] cmd={"cmd","/C","dir "};
try {
//执行命令
process = Runtime.getRuntime().exec(cmd);
//取得命令结果的输出流
InputStream inputStream = process.getInputStream();
//用一个读输出流类去读
InputStreamReader isr = new InputStreamReader(inputStream, Charset.forName("GBK"));
//用缓冲器读行
BufferedReader br = new BufferedReader(isr);
String line=null;
//结果输出流
//直到读完为止
System.out.println("输出");
while ((line=br.readLine())!=null){
System.out.println(line);
}
//错误使出流
System.out.println("错误");
//输出流
InputStream errorStream = process.getErrorStream();
InputStreamReader error = new InputStreamReader(errorStream, Charset.forName("GBK"));
BufferedReader erbr=new BufferedReader(error);
line=null;
while ((line=erbr.readLine())!=null){
System.out.println(line);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
使用多线程的方式读取cmd命令,并把结果输出
package com.ssh;
import sun.rmi.runtime.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class javaExec {
public static void main(String[] args) {
//String[] cmds = new String("cmd", "/c", "dir ");
String[] cmd = {"cmd", "/C", "dir "};
runTimeExecutor(cmd);
}
public static void runTimeExecutor(String[] cmd){
Runtime runtime=Runtime.getRuntime();
try {
Process process = runtime.exec(cmd);
InputStream errorStream = process.getErrorStream();
InputStream inputStream = process.getInputStream();
readStreamInfo(errorStream,inputStream);
int i = process.waitFor();
process.destroy();
if(i==0){
System.out.println("子进程正常完成");
}else{
System.out.println("子进程异常结束");
}
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 读取Runtime.exec运行子进程的输入流
*/
public synchronized static void readStreamInfo(InputStream... inputStreams){
Object o=new Object();
for(InputStream in:inputStreams){
new Thread(()->{
synchronized (o){
System.out.println("start");
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in, Charset.forName("GBK")));
String line=null;
while ((line=br.readLine())!=null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("end");
}
}).start();
}
}
}
StreamGobbler解释
StreamGobbler 是一个 InputStream,它使用内部工作线程不断地使用来自另一个 InputStream 的输入。它使用缓冲区来存储消耗的数据。如果需要,缓冲区大小会自动调整。 这个类有时非常方便——如果你用这个类的实例包装会话的 STDOUT 和 STDERR InputStreams,那么你就不必担心低级 SSH-2 协议中 STDOUT 和 STDERR 的共享窗口,因为所有到达数据将立即被工作线程消耗。此外,作为副作用,流将被缓冲(例如,单字节 read() 操作更快)。 其他用于 Java 库的 SSH 在其 STDOUT 和 STDERR InputStream 实现中默认包含此功能,但是,请注意这种方法也有一个缺点: 如果你调用StreamGobbler的read()方法不够频繁,对端不断发送大量数据,那么你迟早会遇到由于聚合数据导致的内存不足的情况(嗯,这也取决于Java堆尺寸)。无论如何,Joe Average 会喜欢这个类——一个偏执的程序员永远不会使用这种方法。