日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

java连接linux服务器执行shell命令(框架分析+推荐)

發布時間:2024/4/19 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java连接linux服务器执行shell命令(框架分析+推荐) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

java連接linux服務器執行shell命令(框架分析+推薦)

一、分類+連接方式

  • 程序打成jar包,在本地服務器上執行shell命令。這種使用MyRuntimeUtil工具類
  • java程序遠程linux服務器有兩個框架分別是:jsch與ganymed-ssh2框架**。**推薦使用jsch框架因為ganymed-ssh2框架不支持麒麟服務器的連接原因是openssl版本過高,ganymed-ssh框架不維護了所以不支持。
  • 二、執行本地的shell命令

    <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.21</version></dependency>

    工具類

    package com.dameng.util; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.text.StrBuilder; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.log.StaticLog;import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Stack; /*** @author xgt(小光頭)* @version 1.0* @date 2022-3-3 22:40*/ public class MyRuntimeUtil {/*** 執行系統命令,使用系統默認編碼** @param cmds 命令列表,每個元素代表一條命令* @return 執行結果* @throws IORuntimeException IO異常*/public static String execForStr(String... cmds) throws IORuntimeException {return execForStr(CharsetUtil.systemCharset(), cmds);}/*** 執行系統命令,使用系統默認編碼** @param charset 編碼* @param cmds 命令列表,每個元素代表一條命令* @return 執行結果* @throws IORuntimeException IO異常* @since 3.1.2*/public static String execForStr(Charset charset, String... cmds) throws IORuntimeException {return getResult(exec(cmds), charset);}public static String execForErrStr(Charset charset,String cmd) throws IORuntimeException {return getResultErr(exec(cmd), charset);}/*** 執行系統命令,使用系統默認編碼**/public static String execForStr(Charset charset, String cmds) throws IORuntimeException {return getResult(exec(cmds), charset);}/*** 執行系統命令,使用系統默認編碼** @param cmds 命令列表,每個元素代表一條命令* @return 執行結果,按行區分* @throws IORuntimeException IO異常*/public static List<String> execForLines(String... cmds) throws IORuntimeException {return execForLines(CharsetUtil.systemCharset(), cmds);}/*** 執行系統命令,使用系統默認編碼** @param charset 編碼* @param cmds 命令列表,每個元素代表一條命令* @return 執行結果,按行區分* @throws IORuntimeException IO異常* @since 3.1.2*/public static List<String> execForLines(Charset charset, String... cmds) throws IORuntimeException {return getResultLines(exec(cmds), charset);}/*** 執行命令<br>* 命令帶參數時參數可作為其中一個參數,也可以將命令和參數組合為一個字符串傳入** @param cmds 命令* @return {@link Process}*/public static Process exec(String... cmds) {Process process;try {process = new ProcessBuilder(handleCmds(cmds)).redirectErrorStream(true).start();} catch (IOException e) {throw new IORuntimeException(e);}return process;}/*** 執行命令<br>* 命令帶參數時參數可作為其中一個參數,也可以將命令和參數組合為一個字符串傳入** @param cmd 命令* @return {@link Process}*/public static Process exec(String cmd) {Process process;try {// 得到Java進程的相關Runtime運行對象Runtime runtime = Runtime.getRuntime();if(cmd.indexOf("|")>0){String[] cmdArr = {"sh","-c",cmd};process = runtime.exec(cmdArr);}else{process = runtime.exec(cmd);}} catch (IOException e) {throw new IORuntimeException(e);}return process;}/*** 執行命令<br>* 命令帶參數時參數可作為其中一個參數,也可以將命令和參數組合為一個字符串傳入** @param envp 環境變量參數,傳入形式為key=value,null表示繼承系統環境變量* @param cmds 命令* @return {@link Process}* @since 4.1.6*/public static Process exec(String[] envp, String... cmds) {return exec(envp, null, cmds);}/*** 執行命令<br>* 命令帶參數時參數可作為其中一個參數,也可以將命令和參數組合為一個字符串傳入** @param envp 環境變量參數,傳入形式為key=value,null表示繼承系統環境變量* @param dir 執行命令所在目錄(用于相對路徑命令執行),null表示使用當前進程執行的目錄* @param cmds 命令* @return {@link Process}* @since 4.1.6*/public static Process exec(String[] envp, File dir, String... cmds) {try {return Runtime.getRuntime().exec(handleCmds(cmds), envp, dir);} catch (IOException e) {throw new IORuntimeException(e);}}// -------------------------------------------------------------------------------------------------- result/*** 獲取命令執行結果,使用系統默認編碼,獲取后銷毀進程** @param process {@link Process} 進程* @return 命令執行結果列表*/public static List<String> getResultLines(Process process) {return getResultLines(process, CharsetUtil.systemCharset());}/*** 獲取命令執行結果,使用系統默認編碼,獲取后銷毀進程** @param process {@link Process} 進程* @param charset 編碼* @return 命令執行結果列表* @since 3.1.2*/public static List<String> getResultLines(Process process, Charset charset) {InputStream in = null;try {in = process.getInputStream();return IoUtil.readLines(in, charset, new ArrayList<>());} finally {IoUtil.close(in);destroy(process);}}/*** 獲取命令執行結果,使用系統默認編碼,,獲取后銷毀進程** @param process {@link Process} 進程* @return 命令執行結果列表* @since 3.1.2*/public static String getResult(Process process) {return getResult(process, CharsetUtil.systemCharset());}/*** 獲取命令執行結果,獲取后銷毀進程** @param process {@link Process} 進程* @param charset 編碼* @return 命令執行結果列表* @since 3.1.2*/public static String getResult(Process process, Charset charset) {InputStream in = null;InputStream errorStream = null;try {in = process.getInputStream();errorStream = process.getErrorStream();String errorResult = IoUtil.read(errorStream, charset);if(StrUtil.isNotBlank(errorResult)){StaticLog.warn("Shell command execution error, because {}",errorResult);}return IoUtil.read(in, charset);} finally {IoUtil.close(in);IoUtil.close(errorStream);destroy(process);}}/*** 獲取錯誤的執行結果,獲取后銷毀進程** @param process {@link Process} 進程* @param charset 編碼* @return 命令執行結果列表* @since 3.1.2*/public static String getResultErr(Process process, Charset charset) {InputStream in = null;InputStream errorStream = null;try {in = process.getInputStream();errorStream = process.getErrorStream();// System.out.println("252"+IoUtil.read(errorStream, charset));return IoUtil.read(errorStream, charset);} finally {IoUtil.close(in);IoUtil.close(errorStream);destroy(process);}}/*** 獲取命令執行異常結果,使用系統默認編碼,,獲取后銷毀進程** @param process {@link Process} 進程* @return 命令執行結果列表* @since 4.1.21*/public static String getErrorResult(Process process) {return getErrorResult(process, CharsetUtil.systemCharset());}/*** 獲取命令執行異常結果,獲取后銷毀進程** @param process {@link Process} 進程* @param charset 編碼* @return 命令執行結果列表* @since 4.1.21*/public static String getErrorResult(Process process, Charset charset) {InputStream in = null;try {in = process.getErrorStream();return IoUtil.read(in, charset);} finally {IoUtil.close(in);destroy(process);}}/*** 銷毀進程** @param process 進程* @since 3.1.2*/public static void destroy(Process process) {if (null != process) {process.destroy();}}/*** 增加一個JVM關閉后的鉤子,用于在JVM關閉時執行某些操作** @param hook 鉤子* @since 4.0.5*/public static void addShutdownHook(Runnable hook) {Runtime.getRuntime().addShutdownHook((hook instanceof Thread) ? (Thread) hook : new Thread(hook));}/*** 獲得JVM可用的處理器數量(一般為CPU核心數)** @return 可用的處理器數量* @since 5.3.0*/public static int getProcessorCount() {return Runtime.getRuntime().availableProcessors();}/*** 獲得JVM中剩余的內存數,單位byte** @return JVM中剩余的內存數,單位byte* @since 5.3.0*/public static long getFreeMemory() {return Runtime.getRuntime().freeMemory();}/*** 獲得JVM已經從系統中獲取到的總共的內存數,單位byte** @return JVM中剩余的內存數,單位byte* @since 5.3.0*/public static long getTotalMemory() {return Runtime.getRuntime().totalMemory();}/*** 獲得JVM中可以從系統中獲取的最大的內存數,單位byte,以-Xmx參數為準** @return JVM中剩余的內存數,單位byte* @since 5.3.0*/public static long getMaxMemory() {return Runtime.getRuntime().maxMemory();}/*** 獲得JVM最大可用內存,計算方法為:<br>* 最大內存-總內存+剩余內存** @return 最大可用內存*/public static long getUsableMemory() {return getMaxMemory() - getTotalMemory() + getFreeMemory();}/*** 獲取當前進程ID,首先獲取進程名稱,讀取@前的ID值,如果不存在,則讀取進程名的hash值** @return 進程ID* @throws UtilException 進程名稱為空* @since 5.7.3*/public static int getPid() throws UtilException {final String processName = ManagementFactory.getRuntimeMXBean().getName();if (StrUtil.isBlank(processName)) {throw new UtilException("Process name is blank!");}final int atIndex = processName.indexOf('@');if (atIndex > 0) {return Integer.parseInt(processName.substring(0, atIndex));} else {return processName.hashCode();}}/*** 處理命令,多行命令原樣返回,單行命令拆分處理** @param cmds 命令* @return 處理后的命令*/private static String[] handleCmds(String... cmds) {if (ArrayUtil.isEmpty(cmds)) {throw new NullPointerException("Command is empty !");}// 單條命令的情況if (1 == cmds.length) {final String cmd = cmds[0];if (StrUtil.isBlank(cmd)) {throw new NullPointerException("Command is blank !");}cmds = cmdSplit(cmd);}return cmds;}/*** 命令分割,使用空格分割,考慮雙引號和單引號的情況** @param cmd 命令,如 git commit -m 'test commit'* @return 分割后的命令*/private static String[] cmdSplit(String cmd) {final List<String> cmds = new ArrayList<>();final int length = cmd.length();final Stack<Character> stack = new Stack<>();boolean inWrap = false;final StrBuilder cache = StrUtil.strBuilder();char c;for (int i = 0; i < length; i++) {c = cmd.charAt(i);switch (c) {case CharUtil.SINGLE_QUOTE:case CharUtil.DOUBLE_QUOTES:if (inWrap) {if (c == stack.peek()) {//結束包裝stack.pop();inWrap = false;}cache.append(c);} else {stack.push(c);cache.append(c);inWrap = true;}break;case CharUtil.SPACE:if (inWrap) {// 處于包裝內cache.append(c);} else {cmds.add(cache.toString());cache.reset();}break;default:cache.append(c);break;}}if (cache.hasContent()) {cmds.add(cache.toString());}return cmds.toArray(new String[0]);} }

    使用方法

    package java.nio.charset;Charset charset = Charset.forName("UTF-8"); MyRuntimeUtil.execForStr(charset,"ls");

    三、Jsch遠程連接執行

    <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.21</version></dependency><!-- jsch的方式 遠程連接的包--><dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency>

    工具類

    package com.dameng.util;import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.ssh.JschRuntimeException; import com.jcraft.jsch.*;import java.io.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Properties;/*** 執行Shell工具類*/ public class ExecuteShellUtil {/** 未調用初始化方法 錯誤提示信息 */private static final String DONOT_INIT_ERROR_MSG = "please invoke init(...) first!";private static Session session;private ExecuteShellUtil() {}/*** 獲取ExecuteShellUtil類實例對象** @return 實例* @date 2019/4/29 16:58*/public static ExecuteShellUtil getInstance() {return new ExecuteShellUtil();}/*** 初始化** @param ip* 遠程Linux地址* @param port* 端口* @param username* 用戶名* @param password* 密碼* @throws JSchException* JSch異常* @date 2019/3/15 12:41*/public void init(String ip, Integer port, String username, String password) throws JSchException {JSch jsch = new JSch();jsch.getSession(username, ip, port);session = jsch.getSession(username, ip, port);session.setPassword(password);Properties sshConfig = new Properties();sshConfig.put("StrictHostKeyChecking", "no");session.setConfig(sshConfig);session.connect(1200 * 1000);}/*** 執行一條命令*/public String execCmd(String command) throws Exception { // if (session == null || channel == null || channelExec == null) { // throw new Exception(DONOT_INIT_ERROR_MSG); // }// 打開執行shell指令的通道Channel channel = session.openChannel("exec");ChannelExec channelExec = (ChannelExec) channel;channelExec.setCommand("source /etc/profile && source ~/.bash_profile && source ~/.bashrc && adb devices");channelExec.setCommand(command);channel.setInputStream(null);channelExec.setErrStream(System.err);// channel.setXForwarding();channel.connect();StringBuilder sb = new StringBuilder(16);try (InputStream in = channelExec.getInputStream();InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);BufferedReader reader = new BufferedReader(isr)) {String buffer;while ((buffer = reader.readLine()) != null) {sb.append("\n").append(buffer);}return sb.toString();}finally {if (channelExec != null && channelExec.isConnected()) {channelExec.disconnect();}if ( channel != null && channel.isConnected()) {channel.disconnect();}}}/*** 執行一條命令 獲取錯誤流中的內容*/public String execCmdErrContent(String command) throws Exception { // if (session == null || channel == null || channelExec == null) { // throw new Exception(DONOT_INIT_ERROR_MSG); // }// 打開執行shell指令的通道Channel channel = session.openChannel("exec");ChannelExec channelExec = (ChannelExec) channel;channelExec.setCommand(command);channel.setInputStream(null);ByteArrayOutputStream err = new ByteArrayOutputStream();channelExec.setErrStream(err);channel.connect();StringBuilder sb = new StringBuilder(16);try (InputStream in = channelExec.getErrStream();InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);BufferedReader reader = new BufferedReader(isr)) {String buffer;while ((buffer = reader.readLine()) != null) {sb.append("\n").append(buffer);}if(StrUtil.contains(sb.toString(), "沒有那個文件或目錄")){return "";}else{return sb.toString();}}finally {if (channelExec != null && channelExec.isConnected()) {channelExec.disconnect();}if ( channel != null && channel.isConnected()) {channel.disconnect();}}}public static void closeConnect() {if (session != null && session.isConnected()) {session.disconnect();}} }

    使用方法

    package com.dameng;import cn.hutool.core.text.StrSplitter; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.ssh.JschUtil; import com.dameng.util.ExecuteShellUtil; import com.dameng.util.ShellCmdUtil; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import org.junit.Test;import java.math.BigDecimal; import java.util.List;/*** Unit test for simple App.*/ public class JschUtilTest {/*** Jsch方式4830*/@Testpublic void shouldAnswerWithTrue() {long currentTimeMillis = System.currentTimeMillis();ExecuteShellUtil instance = ExecuteShellUtil.getInstance();try {//instance.init("192.168.60.179", 22, "root","password123.1");// String ls = instance.execCmd("top -p 21475 -n 1 -b");String ls = instance.execCmd("cat /opt/dmdbms/log/dm_DW1_01B_202203.log | grep -v 'INFO'");List<String> lineFreedList = StrSplitter.splitByRegex(StrUtil.trimToEmpty(ls), "\n", -1, true, true);for (String s : lineFreedList) {List<String> stringList = StrSplitter.split(StrUtil.trimToEmpty(s), "=", -1, true, true);System.out.println(stringList);}System.out.println(ls);// // // 計算內存使用率(已使用內存/總內存) // String freeStr = instance.execCmd("free | sed -n '2p'"); // List<String> freeInfoList = StrSplitter.splitByRegex(StrUtil.trimToEmpty(freeStr), "\\s+", -1, true, true); // String allMemory = freeInfoList.get(1); // String usedMemory = freeInfoList.get(2); // double f1 = new BigDecimal(Float.valueOf(usedMemory) / Float.valueOf(allMemory)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue() * 100; // // // // // System.out.println(ls); // long currentTimeMillis1 = System.currentTimeMillis(); // System.out.println("Jsch方式"+(currentTimeMillis1-currentTimeMillis));} catch (Exception e) {System.out.println("error info");e.printStackTrace();}} }

    四、ganymed-ssh2遠程連接執行

    <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.21</version></dependency><!-- GanymedUtil的方式 遠程連接的包--><dependency><groupId>ch.ethz.ganymed</groupId><artifactId>ganymed-ssh2</artifactId><version>262</version></dependency>

    工具類

    package com.dameng.util;import ch.ethz.ssh2.Connection; import ch.ethz.ssh2.ConnectionInfo; import ch.ethz.ssh2.Session; import ch.ethz.ssh2.StreamGobbler; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.log.StaticLog; import com.dameng.core.exception.MyGanymedException; import com.dameng.core.exception.MyHostConnectException; import com.dameng.core.exception.MyResolutionException; import com.dameng.domain.OsInfo;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.List;/*** @author xgt(小光頭)* @version 1.0* @date 2022-2-26 15:36*/ public class MyGanymedSingleUtil {private MyGanymedSingleUtil() {}private static Connection connect;private static MyGanymedSingleUtil myGanymedSingleUtil;public static MyGanymedSingleUtil getInstance() {if(myGanymedSingleUtil == null){myGanymedSingleUtil =new MyGanymedSingleUtil();}return myGanymedSingleUtil;}/*** 連接到服務器* @param sshHost 主機* @param sshPort 端口* @return {@link Connection}*/public Connection connect(String sshHost, int sshPort) {connect = new Connection(sshHost, sshPort);try {connect.connect();} catch (IOException e) {throw new IORuntimeException(e);}return connect;}/*** 打開遠程會話** @param sshHost 主機* @param sshPort 端口* @param sshUser 用戶名,如果為null,默認root* @param sshPass 密碼* @return {@link Session}*/public void openConnect(String sshHost, int sshPort, String sshUser, String sshPass) throws MyHostConnectException {// 默認root用戶if (StrUtil.isEmpty(sshUser)) {sshUser = "root";}connect = connect(sshHost, sshPort);try {connect.authenticateWithPassword(sshUser, sshPass);ConnectionInfo connectionInfo = connect.getConnectionInfo();// session = connect.openSession();} catch (IOException e) {throw new MyHostConnectException(e);}}/*** 執行Shell命令(使用EXEC方式)* <p>* 此方法單次發送一個命令到服務端,不讀取環境變量,執行結束后自動關閉Session,不會產生阻塞。* </p>** @param cmd 命令* @param charset 發送和讀取內容的編碼* @return 執行返回結果*/public String exec(String cmd, String charset) throws Exception {final String result;final String stderrStr;ByteArrayOutputStream errStream = new ByteArrayOutputStream();Session session = null;try {session = connect.openSession();Charset charset1 = Charset.forName(charset);session.execCommand(cmd, charset1.name());result = IoUtil.read(new StreamGobbler(session.getStdout()), charset1);//打印錯誤的流輸出IoUtil.copy(new StreamGobbler(session.getStderr()), errStream);stderrStr = new String(errStream.toByteArray(),charset);} finally {session.close();}if(!StrUtil.isEmpty(stderrStr)){throw new MyGanymedException(stderrStr);}return result;}/*** 執行Shell命令* <p>* 此方法單次發送一個命令到服務端,自動讀取環境變量,執行結束后自動關閉Session,不會產生阻塞。* </p>** @param cmd 命令* @param charset 發送和讀取內容的編碼* @param errStream 錯誤信息輸出到的位置* @return 執行返回結果*/public String execByShell(String cmd, Charset charset, OutputStream errStream) {final String result;Session session = null;try {//這個方法有問題session.requestDumbPTY();IoUtil.write(session.getStdin(), charset, true, cmd);result = IoUtil.read(new StreamGobbler(session.getStdout()), charset);if(null != errStream){// 錯誤輸出IoUtil.copy(new StreamGobbler(session.getStdout()), errStream);}} catch (IOException e) {throw new IORuntimeException(e);} finally {close(session);}return result;}/*** 關閉會話**/public void close(Session session) {if(session!=null){session.close();}}/*** 關閉會話**/public void closeConnect() {if(connect!=null){connect.close();}}}

    使用方式

    package com.dameng;import ch.ethz.ssh2.Session; import cn.hutool.extra.ssh.GanymedUtil; import cn.hutool.extra.ssh.JschUtil; import com.dameng.util.ExecuteShellUtil; import com.dameng.util.MyGanymedUtil; import org.junit.Test;import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.nio.charset.Charset;/*** Unit test for simple App.*/ public class GanymedUtilTest {private static String DEFAULTCHART = "UTF-8";/*** Rigorous Test :-)*/@Testpublic void shouldAnswerWithTrue() {long currentTimeMillis = System.currentTimeMillis();// Session session = JschUtil.getSession("192.168.60.177", 22, "root", "root");Session session = MyGanymedUtil.openSession("192.168.60.177", 22, "root", "root");ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();Charset charset = Charset.forName("UTF-8");String ls = MyGanymedUtil.exec(session, "awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \\t]*//;s/[ \\t]*$//'", charset, byteArrayOutputStream);String str = new String(byteArrayOutputStream.toByteArray(),charset);System.out.println(ls);System.out.println("error="+str);long currentTimeMillis1 = System.currentTimeMillis();System.out.println("Ganymed方式"+(currentTimeMillis1-currentTimeMillis));} }

    問題總結

    1. dd命令進行磁盤測速方法獲取不到值

    經過分析發現執行結果都在工具類的錯誤流中,并非在正常流中,自己打印一下錯誤流就發現了。

  • 本地的shell命令的話參考一下工具類的MyRuntimeUtil.execForErrStr(charset,cmd)這個方法。
  • jsch框架的話參考一下工具類的jschInstance.execCmdErrContent(cmd)這個方法。
  • 2. 執行ll命令報錯

    采用框架中的方法調用,是不帶用戶的環境變量的所以ll命令會報錯,ll命令是ls -l命令封裝后的結果。所以需要使用ls -l命令。

    3.執行top命令報錯

    不支持top這種不斷刷新交互式的命令。加參數獲取一次性結果。

    top -b -n 1 |head -n 4 | grep 'sy' | grep 'us' | awk '{print $2}' 與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的java连接linux服务器执行shell命令(框架分析+推荐)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。