Java JSch遠程執(zhí)行Shell命令的方法
背景
項目需求,需要遠程 ssh 登錄到某個節(jié)點執(zhí)行 shell 命令來完成任務。對于這種需求,如果不用 java 程序,直接 linux 的 ssh 命令就可以完成,但是在編碼到程序中時需要相關的程序包來完成,本文主要介紹在 java 中如何使用 JSch 包實現(xiàn) ssh 遠程連接并執(zhí)行命令。
JSch 簡介
JSch 是Java Secure Channel的縮寫。JSch是一個SSH2的純Java實現(xiàn)。它允許你連接到一個SSH服務器,并且可以使用端口轉發(fā),X11轉發(fā),文件傳輸等,當然你也可以集成它的功能到你自己的應用程序??蚣躩sch很老的框架,更新到2016年,現(xiàn)在也不更新了。
JSch 使用 shell 執(zhí)行命令,有兩種方法
- ChannelExec: 一次執(zhí)行一條命令,一般我們用這個就夠了。
- ChannelShell: 可執(zhí)行多條命令,平時開發(fā)用的不多,根據需要來吧;
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");//只能執(zhí)行一條指令(也可執(zhí)行符合指令) ChannelShell channelShell = (ChannelShell) session.openChannel("shell");//可執(zhí)行多條指令 不過需要輸入輸出流
1. ChannelExec
每個命令之間用 ; 隔開。說明:各命令的執(zhí)行給果,不會影響其它命令的執(zhí)行。換句話說,各個命令都會執(zhí)行,但不保證每個命令都執(zhí)行成功。
每個命令之間用 && 隔開。說明:若前面的命令執(zhí)行成功,才會去執(zhí)行后面的命令。這樣可以保證所有的命令執(zhí)行完畢后,執(zhí)行過程都是成功的。
每個命令之間用 || 隔開。說明:|| 是或的意思,只有前面的命令執(zhí)行失敗后才去執(zhí)行下一條命令,直到執(zhí)行成功一條命令為止。
2. ChannelShell
對于ChannelShell,以輸入流的形式,可執(zhí)行多條指令,這就像在本地計算機上使用交互式shell(它通常用于:交互式使用)。如要要想停止,有兩種方式:
發(fā)送一個exit命令,告訴程序本次交互結束;
使用字節(jié)流中的available方法,來獲取數據的總大小,然后循環(huán)去讀。
使用示例
1. 引入 pom 依賴
<dependency> ? ?<groupId>com.jcraft</groupId> ? ?<artifactId>jsch</artifactId> ? ?<version>0.1.53</version> </dependency>
2. jsch 使用示例
在此封裝了一個 Shell 工具類,用來執(zhí)行 shell 命令,具體使用細節(jié)在代碼注釋中有說明,可以直接拷貝并使用,代碼如下:
package org.example.shell; /** ?* Created by qianghaohao on 2021/3/28 ?*/ import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** ?* @description: ?* @author: qianghaohao ?* @time: 2021/3/28 ?*/ public class Shell { ? ? private String host; ? ? private String username; ? ? private String password; ? ? private int port = 22; ? ? private int timeout = 60 * 60 * 1000; ? ? public Shell(String host, String username, String password, int port, int timeout) { ? ? ? ? this.host = host; ? ? ? ? this.username = username; ? ? ? ? this.password = password; ? ? ? ? this.port = port; ? ? ? ? this.timeout = timeout; ? ? } ? ? public Shell(String host, String username, String password) { ? ? ? ? this.host = host; ? ? ? ? this.username = username; ? ? ? ? this.password = password; ? ? } ? ? public String execCommand(String cmd) { ? ? ? ? JSch jSch = new JSch(); ? ? ? ? Session session = null; ? ? ? ? ChannelExec channelExec = null; ? ? ? ? BufferedReader inputStreamReader = null; ? ? ? ? BufferedReader errInputStreamReader = null; ? ? ? ? StringBuilder runLog = new StringBuilder(""); ? ? ? ? StringBuilder errLog = new StringBuilder(""); ? ? ? ? try { ? ? ? ? ? ? // 1. 獲取 ssh session ? ? ? ? ? ? session = jSch.getSession(username, host, port); ? ? ? ? ? ? session.setPassword(password); ? ? ? ? ? ? session.setTimeout(timeout); ? ? ? ? ? ? session.setConfig("StrictHostKeyChecking", "no"); ? ? ? ? ? ? session.connect(); ?// 獲取到 ssh session ? ? ? ? ? ? // 2. 通過 exec 方式執(zhí)行 shell 命令 ? ? ? ? ? ? channelExec = (ChannelExec) session.openChannel("exec"); ? ? ? ? ? ? channelExec.setCommand(cmd); ? ? ? ? ? ? channelExec.connect(); ?// 執(zhí)行命令 ? ? ? ? ? ? // 3. 獲取標準輸入流 ? ? ? ? ? ? inputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getInputStream())); ? ? ? ? ? ? // 4. 獲取標準錯誤輸入流 ? ? ? ? ? ? errInputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getErrStream())); ? ? ? ? ? ? // 5. 記錄命令執(zhí)行 log ? ? ? ? ? ? String line = null; ? ? ? ? ? ? while ((line = inputStreamReader.readLine()) != null) { ? ? ? ? ? ? ? ? runLog.append(line).append("\n"); ? ? ? ? ? ? } ? ? ? ? ? ? // 6. 記錄命令執(zhí)行錯誤 log ? ? ? ? ? ? String errLine = null; ? ? ? ? ? ? while ((errLine = errInputStreamReader.readLine()) != null) { ? ? ? ? ? ? ? ? errLog.append(errLine).append("\n"); ? ? ? ? ? ? } ? ? ? ? ? ? // 7. 輸出 shell 命令執(zhí)行日志 ? ? ? ? ? ? System.out.println("exitStatus=" + channelExec.getExitStatus() + ", openChannel.isClosed=" ? ? ? ? ? ? ? ? ? ? + channelExec.isClosed()); ? ? ? ? ? ? System.out.println("命令執(zhí)行完成,執(zhí)行日志如下:"); ? ? ? ? ? ? System.out.println(runLog.toString()); ? ? ? ? ? ? System.out.println("命令執(zhí)行完成,執(zhí)行錯誤日志如下:"); ? ? ? ? ? ? System.out.println(errLog.toString()); ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } finally { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? if (inputStreamReader != null) { ? ? ? ? ? ? ? ? ? ? inputStreamReader.close(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (errInputStreamReader != null) { ? ? ? ? ? ? ? ? ? ? errInputStreamReader.close(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (channelExec != null) { ? ? ? ? ? ? ? ? ? ? channelExec.disconnect(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (session != null) { ? ? ? ? ? ? ? ? ? ? session.disconnect(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return runLog.toString(); ? ? } }
上述工具類使用:
package org.example; import org.example.shell.Shell; /** ?* Hello world! ?* ?*/ public class App { ? ? public static void main( String[] args ) { ? ? ? ? String cmd = "ls -1"; ? ? ? ? Shell shell = new Shell("192.168.10.10", "ubuntu", "11111"); ? ? ? ? String execLog = shell.execCommand(cmd); ? ? ? ? System.out.println(execLog); ? ? } }
需要注意的點
如果需要后臺執(zhí)行某個命令,不能直接 <命令> + & 的方式執(zhí)行,這樣在 JSch 中不生效,需要寫成這樣的格式:<命令> > /dev/null 2>&1 &。比如要后臺執(zhí)行 sleep 60,需要寫成 sleep 60 > /dev/null 2>&1
具體 issue 見這里:https://stackoverflow.com/questions/37833683/running-programs-using-jsch-in-the-background
參考文檔
https://www.cnblogs.com/slankka/p/11988477.html
https://blog.csdn.net/sinat_24928447/article/details/83022818
到此這篇關于Java JSch遠程執(zhí)行Shell命令的方法的文章就介紹到這了,更多相關Java JSch遠程執(zhí)行Shell命令內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- java中如何執(zhí)行xshell命令
- java在linux本地執(zhí)行shell命令的實現(xiàn)方法
- Java中如何執(zhí)行多條shell/bat命令
- Java程序去調用并執(zhí)行shell腳本及問題總結(推薦)
- 基于Java實現(xiàn)ssh命令登錄主機執(zhí)行shell命令過程解析
- Java代碼執(zhí)行shell命令的實現(xiàn)
- java調用shell命令并獲取執(zhí)行結果的示例
- Shell執(zhí)行/調用Java/Jar程序例子的實例詳解
- java通過ssh連接服務器執(zhí)行shell命令詳解及實例
- Java執(zhí)行shell命令的實現(xiàn)
相關文章
SpringBoot使用AOP實現(xiàn)防重復提交功能
這篇文章主要為大家詳細介紹了SpringBoot如何使用AOP實現(xiàn)防重復提交功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2024-03-03Java編程通過list接口實現(xiàn)數據的增刪改查代碼示例
這篇文章是介紹Java編程基礎方面的內容,涉及l(fā)ist接口的操作,通過list接口實現(xiàn)對數據的增刪改查的相關代碼,具有一定參考價值,需要的朋友可以了解下。2017-10-10Java上傳文件進度條的實現(xiàn)方法(附demo源碼下載)
這篇文章主要介紹了Java上傳文件進度條的實現(xiàn)方法,可簡單實現(xiàn)顯示文件上傳比特數及進度的功能,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2015-12-12Java中SimpleDateFormat 格式化日期的使用
本文主要介紹了Java中SimpleDateFormat 格式化日期的使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03