标签:
我们在日常开发中,有时候会遇到触发一个linux命令,比如清理临时文件,或者触发一个shell命令。那么这个时候就需要通过java去调用shell命令。 这里我们使用java自带的ProcessBuilder 来完成任务。ProcessBuilder类是用于创建操作系统进程。通过本机远程ssh到另外一台机器上去执行shell命令的需求,这种使用方式经常用于一台机器集群管理其他机器的需求。
java里可以通过Ganymed SSH-2, Expect4j等实现ssh登录,基步骤如下:
一、下载安装
从http://www.ganymed.ethz.ch/ssh2/下载,我们用的是ganymed-ssh2-build210.zip。
在eclipse里新建一个测试工程,并将解压后的ganymed-ssh2-build210.jar拷到工程的lib目录下,然后在工程属性的java build path里添加这个jar的library。
二、ssh
将解压后的examples目录下的Basic.java 拷到工程的src目录,编译运行以后可以在控制台看到输出结果。除了执行一条命令,也可以执行一个shell脚本。
测试脚本test.sh:
#! /bin/sh echo "testing shell" ls
运行cmd的Java程序:
public boolean realRun(String cmd) { cmd = test.sh // LocalShellExecutor exe = new LocalShellExecutor(); RmtShellExecutor exe = new RmtShellExecutor("192.168.1.118", "22", "root", "123456"); // RmtShellExecutor exe = new RmtShellExecutor("127.0.0.1", "22", "root", "123456"); logger.info("cmd:" + cmd); int ret = exe.exec(cmd); outErr = exe.getErrorMessage(); outStr = exe.getResult(); result = (ret == 0 ? true : false); if (!result) { logger.error("err:" + outErr); } logger.info("outStr:" + outStr); return result; }
本地调用:
package scnas.controller; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import scnas.iface.ShellExecutor; import scnas.model.Const; public class LocalShellExecutor implements ShellExecutor { /**标准输出**/ private String outStr; /**错误输出**/ private String outErr; @Override public int exec(String cmds) { int ret = -1; try{ final Process process = Runtime.getRuntime().exec(cmds); // Thread inputThread = new Thread(new Runnable(){ // @Override // public void run() // { try { InputStream inputStream = process.getInputStream(); InputStreamReader reader = new InputStreamReader(inputStream); int readed = 0; char[] chs = new char[1024]; StringBuffer buffer = new StringBuffer(); while( (readed=reader.read(chs)) != -1 ){ buffer.append(chs,0,readed); } outStr = buffer.toString(); logger.info(outStr); }catch(Exception ex){ logger.error(ex.getMessage(), ex); } // } // }); // Thread errorThread = new Thread(new Runnable(){ // @Override // public void run() // { try { InputStream inputStream = process.getErrorStream(); InputStreamReader reader = new InputStreamReader(inputStream); int readed = 0; char[] chs = new char[1024]; StringBuffer errorBuffer = new StringBuffer(); while( (readed=reader.read(chs)) != -1 ) { errorBuffer.append(chs,0,readed); } outErr = errorBuffer.toString(); }catch(Exception ex){ logger.error(ex.getMessage(), ex); } // } // }); // errorThread.start(); // inputThread.start(); process.getOutputStream().close(); ret = process.waitFor(); } catch(Exception e){ outErr = e.getMessage(); } if( ret != 0 ) logger.error("LocalShellExecutor ERROR: " + outErr); logger.info("LocalShellExecutor: " + outStr); return ret; } @Override public String getErrorMessage() { return outErr; } @Override public String getResult() { return outStr; } public static void main(String args[]){ LocalShellExecutor localShellExecutor = new LocalShellExecutor(); localShellExecutor.exec(Const.PATH + Const.HOST); } public String getOutStr() { return outStr; } public void setOutStr(String outStr) { this.outStr = outStr; } public String getOutErr() { return outErr; } public void setOutErr(String outErr) { this.outErr = outErr; } private static final Log logger = LogFactory.getLog(LocalShellExecutor.class); }
远程调用:
package scnas.controller; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import scnas.iface.ShellExecutor; import scnas.model.Const; import ch.ethz.ssh2.ChannelCondition; import ch.ethz.ssh2.Connection; import ch.ethz.ssh2.SCPClient; import ch.ethz.ssh2.Session; import ch.ethz.ssh2.StreamGobbler; /** * 远程执行shell脚本类 */ public class RmtShellExecutor implements ShellExecutor{ /** */ private Connection conn; /** 远程机器IP */ private String ip; /** 用户名 */ private String port; private String usr; /** 密码 */ private String psword; private String charset = Charset.defaultCharset().toString(); private static final int TIME_OUT = 1000 * 5 * 60; /**标准输出**/ private String outStr; /**错误输出**/ private String outErr; private static final Log logger = LogFactory.getLog(RmtShellExecutor.class); /** * 构造函数 * @param ip * @param usr * @param ps */ public RmtShellExecutor(String ip, String port, String usr, String ps) { this.ip = ip; this.port = port; this.usr = usr; this.psword = ps; } /** * 登录 * * @return * @throws IOException */ private boolean login() throws IOException { conn = new Connection(ip, Integer.parseInt(port)); conn.connect(); return conn.authenticateWithPassword(usr, psword); } /** * 执行脚本 * * @param cmds * @return * @throws Exception */ @Override public int exec(String cmds){ InputStream stdOut = null; InputStream stdErr = null; int ret = -1; try { if (login()) { // Open a new {@link Session} on this connection Session session = conn.openSession(); // Execute a command on the remote machine. session.execCommand(cmds); stdOut = new StreamGobbler(session.getStdout()); outStr = processStream(stdOut, charset); stdErr = new StreamGobbler(session.getStderr()); outErr = processStream(stdErr, charset); session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT); ret = session.getExitStatus(); } else{ outErr = "登录远程机器失败:" + ip; } }catch(Exception e){ outErr = "远程操作失败:" + ip; }finally{ if (conn != null) { conn.close(); } IOUtils.closeQuietly(stdOut); IOUtils.closeQuietly(stdErr); } if( ret != 0 ){ logger.error("RmtShellExecutor ERROR: " + outErr); // Loginfo loginfo = new Loginfo("ERROR", "", "RmtShellExecutor", cmds + " - " + outStr); // scnasService.loginfoAdd(loginfo); }else{ logger.info(cmds + ": " + outStr); // Loginfo loginfo = new Loginfo("INFO", "", "RmtShellExecutor", cmds + " - " + outErr); // scnasService.loginfoAdd(loginfo); } return ret; } public int exec(String cmds, boolean wait){ int ret = -1; try { if (login()) { // Open a new {@link Session} on this connection Session session = conn.openSession(); // Execute a command on the remote machine. session.execCommand(cmds); session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT ); ret = session.getExitStatus(); } else{ outErr = "登录远程机器失败:" + ip; } }catch(Exception e){ outErr = "远程操作失败:" + ip; }finally{ if (conn != null) { conn.close(); } } if( ret != 0 ) logger.error("RmtShellExecutor wait ERROR!"); return ret; } public void scp(String localfile, String remoteDirectory){ try { if (login()) { SCPClient sCPClient = new SCPClient(conn); sCPClient.put(localfile, remoteDirectory, "0755"); } else{ outErr = "登录远程机器失败:" + ip; } } catch (IOException e) { outErr = "远程操作失败:" + ip; }finally{ if (conn != null) { conn.close(); } } } /** * @param in * @param charset * @return * @throws IOException * @throws UnsupportedEncodingException */ private String processStream(InputStream in, String charset) throws Exception { byte[] buf = new byte[1024]; StringBuilder sb = new StringBuilder(); while (in.read(buf) != -1) { sb.append(new String(buf, charset)); buf = new byte[1024]; } return sb.toString(); } @Override public String getErrorMessage() { return outErr; } @Override public String getResult() { return outStr; } public Connection getConn() { return conn; } public void setConn(Connection conn) { this.conn = conn; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getPort() { return port; } public void setPort(String port) { this.port = port; } public String getUsr() { return usr; } public void setUsr(String usr) { this.usr = usr; } public String getPsword() { return psword; } public void setPsword(String psword) { this.psword = psword; } public String getCharset() { return charset; } public void setCharset(String charset) { this.charset = charset; } public String getOutStr() { return outStr; } public void setOutStr(String outStr) { this.outStr = outStr; } public String getOutErr() { return outErr; } public void setOutErr(String outErr) { this.outErr = outErr; } public static int getTimeOut() { return TIME_OUT; } public static Log getLogger() { return logger; } public static void main(String args[]){ RmtShellExecutor exe = new RmtShellExecutor("10.10.1.101", "22", "root", "123456"); System.out.println(Const.SHELL + Const.PATH + Const.HOST); // System.out.println("exit state:" + exe.exec("gluster volume status vol4 detail")); // System.out.println("result:" + exe.getResult()); // System.out.println("err:" + exe.getErrorMessage()); // exe.scp("/tmp/1", "/tmp"); exe.exec("scnas peer status"); // System.out.println("result:" + exe.getResult()); } }
在eclipse里运行以后的结果为:
Here is some information about the remote host: testing shell 1 test.sh ExitCode: 0
需要注意的是在一个session里只能执行一次命令,因此如果想在server上执行多个命令,要么打开多个session,要么在一个session里去执行一个shell脚本,shell脚本里去执行多个命令。
每次执行完以后,如果正确将返回ExitCode: 0,因此程序里可以通过sess.getExitStatus()来判断命令是否被正确执行。
三、 scp
首先在程序里import ch.ethz.ssh2.SCPClient;
然后通过下面的方法来实现:
SCPClient scpClient = conn.createSCPClient(); scpClient.put("localFiles", "remoteDirectory"); //从本地复制文件到远程目录 scpClient.get("remoteFiles","localDirectory"); //从远程获取文件
如上
public void scp(String localfile, String remoteDirectory){}
例如:
scpClient.put("D:\\localTest.txt", "/home/bill/"); 需要注意的是windows的本地目录要用双斜杠来分隔目录。 scpClient.put("/home/bill/remoteTest.txt", "D:\\");
四、sftp
首先在程序里import ch.ethz.ssh2.SFTPv3Client;
SFTPv3Client sftpClient = new SFTPv3Client(conn); sftpClient.mkdir("newRemoteDir", 0755); //远程新建目录 ,第二个参数是创建的文件夹的读写权限 sftpClient.rmdir("oldRemoteDir"); //远程删除目录
另外还有创建删除文件,读写文件等接口,参见http://www.ganymed.ethz.ch/ssh2/javadoc/ch/ethz/ssh2/SFTPv3Client.html
标签:
原文地址:http://my.oschina.net/u/2260184/blog/512114