[メモ] Javaで外部コマンドを実行する

2 min read読了の目安(約2200字

たまに使うけど、だいたい忘れてるのでメモ。

とりあえずシンプルに

とりあえずこんな感じ。それにしてもInputStreamをStringにするのは昔に比べて随分らくになったよなー.

    public static void main(String[] args) throws Exception {
        var result = execCommand("ls", "-l");

        System.out.print(result.get("stdout"));
        System.err.print(result.get("stderr"));

	System.out.println("status: " + result.get("status"));
    }

    Map<String, String> execCommand(String... cmds) throws IOException, InterruptedException {
        var result = new HashMap<String, String>();
        var proc = Runtime.getRuntime().exec(cmds);

        result.put("stdout", toString(proc.getInputStream()));
        result.put("stderr", toString(proc.getErrorStream()));
        result.put("status", Integer.toString(proc.waitFor()));

        return result;
    }

    String toString(InputStream input){
        try (var xs = new BufferedReader(new InputStreamReader(input)).lines()) {
            return xs.collect(Collectors.joining(System.lineSeparator()));
        }
    }

中身は下記辺りを参照すると詳しく書いてある。

https://www.ne.jp/asahi/hishidama/home/tech/java/process.html
https://chat-messenger.com/blog/java/runtime-getruntime-exec

逐次表示

上記のコードだとよく考えたら逐次表示されないのでコールバックを取る形にちょっと修正。クラス定義とかちゃんとすればもう少しシンプルなAPIになると思うけど、とりあえずこんな感じで。

    Map<String, String> execCommand(Consumer<String> stdProc, Consumer<String> errProc, String... cmds)
            throws IOException, InterruptedException {
        var result = new HashMap<String, String>();
        var proc = Runtime.getRuntime().exec(cmds);

        result.put("stdout", read(proc.getInputStream(), (s) -> System.out.println(s)));
        result.put("stderr", read(proc.getErrorStream(), (s) -> System.err.println(s)));
        result.put("status", Integer.toString(proc.waitFor()));

        return result;
    }

    String read(InputStream input, Consumer<String> callback) {
        var sb = new StringBuilder();
        try (Stream<String> s = new BufferedReader(new InputStreamReader(input)).lines()) { // 自動close
            s.map((l) -> {
                sb.append(l);
                sb.append(System.lineSeparator());
                return l;
            }).forEach(callback);
        }
        return sb.toString();
    }

Happy Hacking!