Java 执行shell复杂参数工具类

1,224 阅读1分钟
ffmpeg 集成的时候封装了一个java调用shell的工具类

依赖

<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-exec</artifactId>
	<version>1.3</version>
</dependency>

代码

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.*;
import org.apache.commons.lang3.exception.ExceptionUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Slf4j
public class CommandUtils {

    private static final String DEFAULT_CHARSET = "UTF-8";
    private static final Long TIMEOUT = 1000L * 60;

    static {
        log.info("[------当前shell路径[{}]------]", exeCommand("pwd"));
    }

    public synchronized static String exeCommand(String command) throws RuntimeException {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            int exitCode = exeCommand(command, out);
            if (exitCode == 0) {
                log.info("[{}]-命令运行成功,耗时[{}]", command, System.currentTimeMillis());
            } else {
                log.info("[{}]-命令运行失败,耗时[{}]", command, System.currentTimeMillis());
            }
            return out.toString(DEFAULT_CHARSET);
        } catch (Exception e) {
            log.info(ExceptionUtils.getStackTrace(e));
            throw new RuntimeException(ExceptionUtils.getStackTrace(e));
        }
    }


    public synchronized static int exeCommand(String command, OutputStream out) throws IOException {
        log.info("[shell]-[{}]", command);
        String[] shellDesc = command.split(" ");
        CommandLine commandLine = CommandLine.parse(command);
        if (shellDesc.length > 1) {
            commandLine = new CommandLine(shellDesc[0]);
            for (int i = 1; i < shellDesc.length; i++) {
                commandLine.addArgument(shellDesc[i]);
            }
        }
        PumpStreamHandler pumpStreamHandler = null;
        if (null == out) {
            pumpStreamHandler = new PumpStreamHandler();
        } else {
            pumpStreamHandler = new PumpStreamHandler(out);
        }

//        ExecuteWatchdog.INFINITE_TIMEOUT
        ExecuteWatchdog watchdog = new ExecuteWatchdog(TIMEOUT);
        DefaultExecutor executor = new DefaultExecutor();
        executor.setStreamHandler(pumpStreamHandler);
        executor.setWatchdog(watchdog);
        return executor.execute(commandLine);
    }

    public static List<String> getShellResultLines(String result) {
        if (result != null) {
            log.info("[getShellResultLines]-[{}]", result);
            result = result.replaceAll("\\r\\n", "\\n ");
            log.info("[getShellResultLines]-[{}]", result);
            String[] resultLines = result.split("\\n");
            return Arrays.asList(resultLines);
        }
        return Collections.emptyList();
    }}

常见问题

commons-exec,在执行的时候会返回一些自定义错误码,比如143。但是在shell中所有非0的错误码,都是没有意义的。
所以可以根据日志手动执行一遍shell命令,来判断错误原因。
博主列出经常碰到的不同错误码原因
  1. shell命令参数中带有复杂的参数,例如url,请参考使用 commandLine.addArgument(shellDesc[i]) 的方式添加参数。
  2. 执行shell命令,是否是在 bin/
  3. 在shell命令中,是否存在需要权限的指令,比如 mkdir
  4. 执行命令中是否超时,上面的代码设置的是60超时,不确定时间的情况可以尝试 ExecuteWatchdog.INFINITE_TIMEOUT 无穷大设置。