咱們在平常開發中,有時候會遇到觸發一個linux命令,好比清理臨時文件,或者觸發一個shell命令。那麼這個時候就須要經過java去調用shell命令。 這裏咱們使用java自帶的ProcessBuilder 來完成任務。ProcessBuilder類是用於建立操做系統進程。經過本機遠程ssh到另一臺機器上去執行shell命令的需求,這種使用方式常常用於一臺機器集羣管理其餘機器的需求。html
java裏能夠經過Ganymed SSH-2, Expect4j等實現ssh登陸,基步驟以下:java
1、下載安裝linux
從http://www.ganymed.ethz.ch/ssh2/下載,咱們用的是ganymed-ssh2-build210.zip。shell
在eclipse裏新建一個測試工程,並將解壓後的ganymed-ssh2-build210.jar拷到工程的lib目錄下,而後在工程屬性的java build path裏添加這個jar的library。apache
2、sshwindows
將解壓後的examples目錄下的Basic.java 拷到工程的src目錄,編譯運行之後能夠在控制檯看到輸出結果。除了執行一條命令,也能夠執行一個shell腳本。session
測試腳本test.sh:
app
#! /bin/sh echo "testing shell" ls
運行cmd的Java程序:eclipse
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; }
本地調用:ssh
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()來判斷命令是否被正確執行。
3、 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:\\");
4、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