Java 學習筆記(三)調用 bat 或 shell 腳本執行


一、背景

     在某些程序中需要 Java 代碼直接 調用 bat 腳本或 sh 腳本 執行,但是除了命令不一樣以外,所有的邏輯是一樣的,為此以下給出通用代碼。

二、示例 + 說明

package com.example.demo.tool;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang3.StringUtils;

import com.example.demo.test.StreamManage;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CmdUtils {
    private static AtomicBoolean error = new AtomicBoolean(false);

    /*
     * 啟動程序
     */
    public static synchronized boolean startApp(String appParentAbsolute) {
        String osName = System.getProperty("os.name");
        String[] cmds = null;
        try {
            if (osName.toLowerCase().contains("windows")) { // windows 平台
                cmds = new String[] { "cd /d \"" + appParentAbsolute + File.separator + "script" + "\"",
                        "start.bat>start.log" };    // 多條命令
                exec4Windows(cmds);
            } else if (osName.toLowerCase().contains("linux")) { // linux平台
                cmds = new String[] { "cd \"" + appParentAbsolute + File.separator + "script" + "\"",
                        "./start.sh>start.log" };  // 多條命令
                exec4Linux(cmds);
            }
            return true;
        } catch (IOException e) {
            log.error("start app fail", e);
        } catch (InterruptedException e) {
            log.error("start app fail", e);
        } catch (IllegalAccessError e) {
            log.error("start app fail", e);
        }
        return false;
    }

    /*
     * 停止程序
     */
    public static synchronized boolean stopApp(String appParentAbsolute) {
        String osName = System.getProperty("os.name");
        String[] cmds = null;
        try {
            if (osName.toLowerCase().contains("windows")) { // windows 平台
                cmds = new String[] { "cd /d \"" + appParentAbsolute + File.separator + "script" + "\"",
                        "start /b stop.bat>stop.log" };
                exec4Windows(cmds);  // 多條命令
            } else if (osName.toLowerCase().contains("linux")) { // linux平台
                cmds = new String[] { "cd \"" + appParentAbsolute + File.separator + "script" + "\"",
                        "./stop.sh>stop.log" };   // 多條命令
                exec4Linux(cmds);
            }
            return true;
        } catch (IOException e) {
            log.error("stop app fail", e);
        } catch (InterruptedException e) {
            log.error("stop app fail", e);
        } catch (IllegalAccessError e) {
            log.error("stop app fail", e);
        }
        return false;
    }
private static String exec4Windows(String[] commands) throws IOException, InterruptedException {
        String cmd = Joiner.on("&&").join(commands);
        log.info("exec cmd : {}", cmd);
        return exec("cmd /c " + cmd);  // 注意這里 將多條 windows 命令使用 && 進行拼接形成字符串,同時 在拼接字符串開頭使用 cmd /c 
    }

    private static String exec4Linux(String[] commands) throws IOException, InterruptedException {
        String cmd = Joiner.on("&&").join(commands);
        log.info("exec cmd : {}", cmd);
        return exec(new String[]{"/bin/bash","-c",cmd});   // 注意這里 將多條 linux 命令使用 && 進行拼接形成字符串,但是這里沒有在拼接的字符串開頭加上 /bin/bash -c 
經過驗證直接 同windows一樣拼接字符串去執行時不可行的, 只能作為一個 字符串數組 調用 Runtime.getRuntime().exec(String[])方法進行執行
}
private static String exec(String[] commandArray) throws IOException, InterruptedException { Process process;// Process可以控制該子進程的執行或獲取該子進程的信息 log.info("exec cmd : {}", Joiner.on(" ").join(commandArray)); process = Runtime.getRuntime().exec(commandArray);// exec()方法指示Java虛擬機創建一個子進程執行指定的可執行程序,並返回與該子進程對應的Process對象實例。 return execBase(process); } private static String exec(String commands) throws IOException, InterruptedException { Process process;// Process可以控制該子進程的執行或獲取該子進程的信息 log.info("exec cmd : {}", commands); process = Runtime.getRuntime().exec(commands);// exec()方法指示Java虛擬機創建一個子進程執行指定的可執行程序,並返回與該子進程對應的Process對象實例。 return execBase(process); } private static String execBase(Process process) throws IOException, InterruptedException { // 下面兩個可以獲取輸入輸出流 InputStream errorStream = process.getErrorStream(); InputStream inputStream = process.getInputStream(); String result = StringUtils.EMPTY; StreamManage stream = new StreamManage(inputStream, "normal"); StreamManage errorStreamThread = new StreamManage(errorStream, "Error"); stream.setName("normal"); stream.start(); errorStreamThread.setName("Error"); errorStreamThread.start(); int exitStatus = 0; exitStatus = process.waitFor();// 等待子進程完成再往下執行,返回值是子線程執行完畢的返回值 // 第二種接受返回值的方法 int i = process.exitValue(); // 接收執行完畢的返回值 log.debug("i----" + i); if (exitStatus != 0) { log.error("exec cmd exitStatus {}", exitStatus); } else { log.debug("exec cmd exitStatus {}", exitStatus); } errorStreamThread.setEnd(true); stream.setEnd(true); process.destroy(); // 銷毀子進程 process = null; if (exitStatus != 0 || StringUtils.isNotEmpty(errorStreamThread.getResult())) { result = errorStreamThread.getResult(); throw new IllegalAccessError("exe fail,message:" + result); } else if (StringUtils.isNotEmpty(stream.getResult())) { result = stream.getResult(); } return result; } }

 接收返回的數據流

package com.example.demo.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class StreamManage extends Thread{
    private InputStream inputStream;
    private String type;
    private String result;
    boolean end = false;

    //StreamManage的構造參數是InputStream類實例 => 實際上是Process實例的返回流
    public StreamManage(InputStream inputStream,String type){
        this.inputStream = inputStream;
        this.type = type;
        this.end = false;
    }
    public void run(){
        log.info("start thread to read cmd ");
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream,Charset.forName("GBK"));
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String line = null;
        StringBuffer resultBuffer = new StringBuffer();
        try{
            while(!end){
                if((line = bufferedReader.readLine())!=null){
                    if (type.equals("Error")) {
                        log.error(line);
                    }else{
                        log.debug(line);
                    }
                    resultBuffer.append(line);
                    resultBuffer.append("\r\n");
                }
            }
            log.info("result:[{}]", resultBuffer.toString());
            result = resultBuffer.toString();
        }catch (IOException e){
            //ignore
        }catch(Throwable e){
            log.warn("cmd fail.",e);
        }finally{
            end = true;
        }
    }
    public String getResult() {
        return result;
    }
    public boolean isEnd() {
        return end;
    }
    public void setEnd(boolean end) {
        this.end = end;
    }    
}

這里需要強調的是:

  通過 Runtime.getRuntime().exec() 直接執行 Linux 命令 或調用 Linux 腳本的時候,只能使用 通過方法 Runtime.getRuntime().exec(new String[]{"/bin/bash","-c",commond}) 方法,否則執行不了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM