Java执行shell命令
Posted ice&wind
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java执行shell命令相关的知识,希望对你有一定的参考价值。
Java执行shell命令
前言
java执行shell命令的方式有很多种,但是在应用的过程中,我们可能会遇上一些特殊的情况,导致执行脚本失败,不生效的场景。
一、案例
场景
- java服务,如果需要服务自动重启。那么我们通过java执行shell命令,使用常用jdk的方法:Runtime.getRuntime().exec(command)的方式,重启服务,可能会导致重启失败。
原因
- java执行本地命令启动的是一个子进程处理,默认情况下子进程与父进程I/O通过管道相连(ProcessBuilder.Redirect.PIPE)
- 当服务执行自身重启命令时,父进程关闭导致管道连接中断,将导致子进程也崩溃,而无法完成后续启动
解决方案
- 设置子进程的I/O源或目标将与当前进程的相同,两者相互独立
- 设置子进程IO输出重定向到指定文件
这里我们采用第一种解决方案
ProcessBuilder pb = new ProcessBuilder("service","java-service","restart");
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.start();
ProcessBuilder 也是J2SE1.5 就有了的类。此类用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法。在J2SE 1.5之前,都是由Process类处来实现进程的控制管理。
static ProcessBuilder.Redirect DISCARD
表示将丢弃子进程输出。
static ProcessBuilder.Redirect INHERIT
表示子进程I / O源或目标将与当前进程的相同。
static ProcessBuilder.Redirect PIPE
表示子进程I / O将通过管道连接到当前Java进程。
ProcessBuilder 可配置执行脚本的子进程I / O源或目标将与当前进程的相同。绑定之后,执行重启,就能成功,管道不会断开。
ProcessBuilder 可参考连接:
ProcessBuilder api
ProcessBuilder 中文文档
二、拓展
创建临时脚本,执行shell命令
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
可直接复制使用,注意引入maven包
public static String runAndResult(String cmd)
StringBuilder sb = new StringBuilder();
BufferedReader br = null;
boolean execFlag = true;
String uuid = UUID.randomUUID().toString().replace("-","");
String tempFileName = "./temp" + uuid +".sh";
try
String osName = System.getProperty("os.name").toUpperCase(Locale.ENGLISH);
if (osName.matches("^(?i)LINUX.*$") || osName.contains("MAC"))
FileWriter execute_fw = new FileWriter(tempFileName);
BufferedWriter execute_bw=new BufferedWriter(execute_fw);
execute_bw.write(cmd + "\\n");
execute_bw.close();
execute_fw.close();
String command ="bash " + tempFileName;
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null)
sb.append(System.lineSeparator());
sb.append(line);
br.close();
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = br.readLine()) != null)
sb.append(System.lineSeparator());
sb.append(line);
if (line.length() > 0)
execFlag = false;
br.close();
if (execFlag)
else
throw new RuntimeException(sb.toString());
else
throw new RuntimeException("不支持的操作系统类型");
catch (Exception e)
log.error("执行失败",e);
finally
if (br != null)
try
br.close();
catch (IOException e)
log.error("io异常",e);
FileUtils.deleteQuietly(new File(tempFileName));
return sb.toString();
三、总结
实践是检验真理的唯一标准,工作生活中一定要多总结,记录。如果你觉得有用,点个赞吧。收藏一下也是不错的。
java程序执行,调用shell命令和shell脚本
坑呀!记得在start()之后, waitFor()之前把缓冲区读出来打log,否则是阻塞缓冲区,没有输出的
package com.jikexueyuancrm.util; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.lang.management.ManagementFactory; import java.util.List; import org.apache.log4j.Logger; import com.jikexueyuancrm.controller.AnHui; /** * ShellUtils * <ul> * <strong>Check root</strong> * <li>{@link ShellUtils#checkRootPermission()}</li> * </ul> * <ul> * <strong>Execte command</strong> * <li>{@link ShellUtils#execCommand(String, boolean)}</li> * <li>{@link ShellUtils#execCommand(String, boolean, boolean)}</li> * <li>{@link ShellUtils#execCommand(List, boolean)}</li> * <li>{@link ShellUtils#execCommand(List, boolean, boolean)}</li> * <li>{@link ShellUtils#execCommand(String[], boolean)}</li> * <li>{@link ShellUtils#execCommand(String[], boolean, boolean)}</li> * </ul> * * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16 */ /** * @author yuan hai * 使用Runtime.getRuntime().exec */ public class ShellUtils { private static Logger log = Logger.getLogger(ShellUtils.class); public static final String COMMAND_SU = "su"; public static final String COMMAND_SH = "sh"; public static final String COMMAND_EXIT = "exit\n"; public static final String COMMAND_LINE_END = "\n"; private ShellUtils() { throw new AssertionError(); } /** * check whether has root permission * * @return */ public static boolean checkRootPermission() { return execCommand("echo root", true, false).result == 0; } /** * execute shell command, default return result msg * * @param command command * @param isRoot whether need to run with root * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(String command, boolean isRoot) { return execCommand(new String[] {command}, isRoot, true); } /** * execute shell commands, default return result msg * * @param commands command list * @param isRoot whether need to run with root * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(List<String> commands, boolean isRoot) { return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, true); } /** * execute shell commands, default return result msg * * @param commands command array * @param isRoot whether need to run with root * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(String[] commands, boolean isRoot) { return execCommand(commands, isRoot, true); } /** * execute shell command * * @param command command * @param isRoot whether need to run with root * @param isNeedResultMsg whether need result msg * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) { return execCommand(new String[] {command}, isRoot, isNeedResultMsg); } /** * execute shell commands * * @param commands command list * @param isRoot whether need to run with root * @param isNeedResultMsg whether need result msg * @return * @see ShellUtils#execCommand(String[], boolean, boolean) */ public static CommandResult execCommand(List<String> commands, boolean isRoot, boolean isNeedResultMsg) { return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, isNeedResultMsg); } /** * execute shell commands * * * 最基础方法 * @param commands command array * @param isRoot whether need to run with root * @param isNeedResultMsg whether need result msg * @return <ul> * <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and * {@link CommandResult#errorMsg} is null.</li> * <li>if {@link CommandResult#result} is -1, there maybe some excepiton.</li> * </ul> */ public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) { int result = -1; if (commands == null || commands.length == 0) { return new CommandResult(result, null, null); } Process process = null; BufferedReader successResult = null; BufferedReader errorResult = null; StringBuilder successMsg = null; StringBuilder errorMsg = null; DataOutputStream os = null; try { process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); os = new DataOutputStream(process.getOutputStream()); for (String command : commands) { if (command == null) { continue; } // donnot use os.writeBytes(commmand), avoid chinese charset error os.write(command.getBytes()); os.writeBytes(COMMAND_LINE_END); os.flush(); } os.writeBytes(COMMAND_EXIT); os.flush(); // get command result if (isNeedResultMsg) { successMsg = new StringBuilder(); errorMsg = new StringBuilder(); successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); String s; while ((s = successResult.readLine()) != null) { successMsg.append(s).append("\n"); } while ((s = errorResult.readLine()) != null) { errorMsg.append(s).append("\n"); } } result = process.waitFor(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (os != null) { os.close(); } if (successResult != null) { successResult.close(); } if (errorResult != null) { errorResult.close(); } } catch (IOException e) { e.printStackTrace(); } if (process != null) { process.destroy(); } } log.info("result:"+result); if( successMsg != null) log.info("successMsg:"+successMsg.toString()); if( errorMsg != null) log.info("errorMsg:"+errorMsg.toString()); return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null : errorMsg.toString()); } /** * result of command * <ul> * <li>{@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in * linux shell</li> * <li>{@link CommandResult#successMsg} means success message of command result</li> * <li>{@link CommandResult#errorMsg} means error message of command result</li> * </ul> * * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16 */ public static class CommandResult { /** result of command **/ public int result; /** success message of command result **/ public String successMsg; /** error message of command result **/ public String errorMsg; public CommandResult(int result) { this.result = result; } public CommandResult(int result, String successMsg, String errorMsg) { this.result = result; this.successMsg = successMsg; this.errorMsg = errorMsg; } } public static void main(String[] args) throws Exception { // String[] cmd=new String[]{"ps aux","pwd","ls -al"}; //执行shell命令 // execCommand(cmd,false, true); //执行shell脚本 String[] script=new String[]{"/bin/bash /home/smgadmin/test/soyoung_comment/shell/crawler.sh start "}; execCommand(script,false, true); //使用ProcessBuilder // exeCmd("ps aux;ls -al;pwd");//执行linux命令 // exeCmd("dir&dir");//执行windows命令一行多命令用&分隔 } //使用ProcessBuilder /** * @author yuan hai 2016年12月9日 * @param shell shell可以传入多个命令 ,例如:"ps aux;ls -al;pwd" * @return * @throws IOException */ public static int exeCmd(String shell) throws IOException { int success = 0; StringBuffer sb = new StringBuffer(); BufferedReader br = null; // get name representing the running Java virtual machine. String name = ManagementFactory.getRuntimeMXBean().getName(); String pid = name.split("@")[0]; try { System.out.println("Starting to exec{ " + shell + " }. PID is: " + pid); Process process = null; //执行脚本时,不要加-c // 当执行系统的命令时,才会加-c //linux命令行 ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", shell); //windows命令行 // ProcessBuilder pb = new ProcessBuilder("cmd", "/c", shell); pb.environment(); pb.redirectErrorStream(true); // merge error stream into standard stream process = pb.start(); if (process != null) { br = new BufferedReader( new InputStreamReader(process.getInputStream(),"GBK"), 1024); } else { System.out.println("There is no PID found."); } sb.append("Ending exec right now, the result is:\n"); String line = null; while (br != null && (line = br.readLine()) != null) { sb.append(line).append("\n"); } //记得在start()之后, waitFor()之前把缓冲区读出来打log process.waitFor(); } catch (Exception ioe) { sb.append("Error occured when exec cmd:\n").append(ioe.getMessage()).append("\n"); } finally { PrintWriter writer = null; if (br != null) { br.close(); } try { writer = new PrintWriter(System.out); writer.write(sb.toString()); } catch (Exception e) { log.error(e.getMessage(), e); } finally { writer.close(); } success = 1; } return success; } }
参考文章:
阿里大牛文章:
https://yq.aliyun.com/articles/2362
本文出自 “点滴积累” 博客,请务必保留此出处http://tianxingzhe.blog.51cto.com/3390077/1881330
以上是关于Java执行shell命令的主要内容,如果未能解决你的问题,请参考以下文章