当前位置: 首页 > news >正文

java操作linux

文章目录

  • 远程连接服务器
  • 执行linux命令或shell脚本
    • 介绍
      • Process的方法
      • 相关类UML
    • 工具类
      • 基本工具类
      • 依赖第三方的工具类

远程连接服务器

java程序远程linux服务器有两个框架分别是:jsch与ganymed-ssh2框架。推荐使用jsch框架,因为ganymed-ssh2框架不支持麒麟服务器的连接,原因是openssl版本过高,ganymed-ssh框架不维护了所以不支持。

import cn.hutool.core.text.StrSplitter;
import cn.hutool.core.util.StrUtil;
import com.jcraft.jsch.*;import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Properties;/*** 远程连接linux服务并执行命令* 网上查询经过验证可以使用<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.21</version></dependency><dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency>*/
public class ShellUtils {private static Session session;private ShellUtils() {}public static ShellUtils getInstance() {return new ShellUtils();}/*** 初始化* @throws JSchException JSch异常*/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 {// 打开执行shell指令的通道Channel channel = session.openChannel("exec");ChannelExec channelExec = (ChannelExec) channel;String cmd = "source /etc/profile && source ~/.bash_profile " +"&& source ~/.bashrc &&  adb devices";channelExec.setCommand(cmd);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(buffer);}} finally {if (channelExec != null && channelExec.isConnected()) {channelExec.disconnect();}if (channel != null && channel.isConnected()) {channel.disconnect();}}return sb.toString();}// 执行一条命令 获取错误流中的内容public String execCmdErrContent(String command) throws Exception {// 打开执行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();}}public static void main(String[] args) {ShellUtils instance = ShellUtils.getInstance();try {instance.init("192.168.81.122", 22, "root", "test1");String cmd = "ps -ef | grep monitor-0.0.1-SNAPSHOT.jar " +"| grep -v xjar|grep -v grep | awk '{print $2}'";String ls = instance.execCmd(cmd);
//            String cmd = "cat /opt/dmdbms/log/dm_DW1_01B_202203.log " +
//                    "| grep -v 'INFO'";
//            String ls = instance.execCmd(cmd);
//            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 cmd1 = "free | sed -n '2p'";
//            String freeStr = instance.execCmd(cmd1);
//            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);} catch (Exception e) {System.out.println("error info");e.printStackTrace();} finally {ShellUtils.closeConnect();}}
}

执行linux命令或shell脚本

在Java中,调用runtime线程执行脚本是非常消耗资源的,所以切记不要频繁使用!
在调用runtime去执行脚本的时候,其实就是JVM开了一个子线程去调用JVM所在系统的命令,其中开了三个通道:输入流、输出流、错误流,其中输出流就是子线程走调用的通道。
大家都知道,waitFor是等待子线程执行命令结束后才访问,但是在runtime中,打开程序的命令如果不关闭,就不算子线程结束,比如如下代码。

private static Process p = null;
p = Runtime.getRuntime().exec("notepad.exe");
p.waitFor();
System.out.println("---------------我被执行了");

以上代码中,打开windows中记事本,如果我们不手动关闭记事本,那么输出语句就不会执行,这点是需要理解的。

介绍

// 在单独的进程中执行指定的字符串命令
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[] encp,File dir)
// 在指定环境和工作目录的独立进程中执行指定的命令和变量
public Process exec(String[] cmdarray,String[] envp,File dir)
  • cmdArray: 包含所调用命令及其参数的数组。
    • 如果把命令放到一个String[]中时,必须把命令中每个部分作为一个元素存在String[]中,或者是把命令按照空格符分割得到的String[]。
//right
String[] cmdArray = {"tar", "-cf", tarName, fileName};
//error
String[] cmdArray = {"tar -cf", tarName, fileName};
  • command: 一条指定的系统命令。
  • envp: 字符串数组,其中每个元素的环境变量的设置格式为name=value;如果子进程应该继承当前进程的环境,则该参数为 null。
    • 模拟环境变量
val=2
call=Bash Shell
  • 测试shell脚本
#!/usr/bin/env bashargs=1
if [ $# -eq 1 ];thenargs=$1echo "The argument is: $args"
fiecho "This is a $call"
start=`date +%s`
sleep 3s
end=`date +%s`
cost=$((($end - $start) * $args * $val))
echo "Cost Time: $cost"
  • 调用
String cmd = "sh " + script + " " + args;
String[] evnp = {"val=2", "call=Bash Shell"};
process = Runtime.getRuntime().exec(cmd, evnp);
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())
);
String line = "";
while ((line = input.readLine()) != null) {System.out.println(line);
}
input.close();
  • 返回结果
/root/experiment/
The argument is: 4
This is a Bash Shell
Cost Time: 24
  • dir: 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为 null。

Process的方法

  • destroy():杀掉子进程
  • exitValue():返回子进程的出口值,值0表示正常终止
  • getErrorStream():获取子进程的错误流
  • getInputStream():获取子进程的输入流
  • getOutputStream():获取子进程的输出流
  • waitFor():导致当前线程等待,如有必要,一直要等到由该Process对象表示的进程已经终止。如果已终止该子进程,此方法立即返回。如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程,0表示正常终止。

相关类UML

java.lang.Runtime
在这里插入图片描述
java.lang.Process
在这里插入图片描述

工具类

基本工具类

package utils;import java.io.BufferedReader;
import java.io.InputStreamReader;public class ShellUtils {//执行shell命令并获取输出结果public static String execAndResult(String cmd){System.out.println("cmd: " + cmd);String result = "";try {Runtime runtime = Runtime.getRuntime();Process ps = runtime.exec(cmd);//获取执行结果的输入BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));StringBuffer sb = new StringBuffer();String line;while ((line = br.readLine()) != null) {//执行结果加上回车sb.append(line);}result = sb.toString();br.close();System.out.println("waitFor:" + ps.waitFor());} catch (Exception e) {e.printStackTrace();}return result;}public static void main(String[] args) {//执行普通命令execAndResult("shutdown -r");//执行脚本execAndResult("sh /data/jqxt/script/bak_pz.sh");}
}

依赖第三方的工具类

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;/**<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.21</version></dependency>*/
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]);}
}

相关文章:

  • Covalent Network(CQT)推出以太坊质押迁移计划,以增强长期结构化数据可用性、塑造万亿级 LLM 参数体系
  • 输入输出系统的发展历程
  • python + jdbc 连接 达梦数据库
  • 在Linux系统上实现TCP(socket)通信
  • c++20协程详解(三)
  • 19、差分矩阵
  • (Oracle)SQL优化技巧(一):分页查询
  • 计算机基础系列合集
  • 面试准备 集合 List
  • Python 新手最容易踩的坑
  • Scrapy 爬取m3u8视频
  • 基于springboot实现墙绘产品展示交易平台管理系统项目【项目源码+论文说明】
  • 基于BP神经网络的时间序列预测模型matlab代码
  • Spark-Scala语言实战(11)
  • loopvar 改动不同版本的影响-并发
  • [译] React v16.8: 含有Hooks的版本
  • C++类中的特殊成员函数
  • conda常用的命令
  • docker-consul
  • java8 Stream Pipelines 浅析
  • JavaScript异步流程控制的前世今生
  • JAVA并发编程--1.基础概念
  • laravel 用artisan创建自己的模板
  • leetcode46 Permutation 排列组合
  • Python_OOP
  • 浮动相关
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 技术胖1-4季视频复习— (看视频笔记)
  • 免费小说阅读小程序
  • 普通函数和构造函数的区别
  • 优秀架构师必须掌握的架构思维
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • MyCAT水平分库
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (Note)C++中的继承方式
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (vue)页面文件上传获取:action地址
  • (补)B+树一些思想
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (剑指Offer)面试题34:丑数
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)四层和七层负载均衡的区别
  • .naturalWidth 和naturalHeight属性,
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .NET Standard 的管理策略
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .NET委托:一个关于C#的睡前故事
  • .ui文件相关
  • @基于大模型的旅游路线推荐方案
  • [④ADRV902x]: Digital Filter Configuration(发射端)
  • [BZOJ 1040] 骑士