Como executar um comando do shell em Java

Como executar um comando do shell em Java

1. Visão geral

Com este tutorial, ilustraremos as duas maneiras deexecuting a shell command from within Java code.

A primeira é usar a classeRuntime e chamar seu métodoexec.

A segunda maneira, mais personalizável, será criar e usar uma instânciaProcessBuilder.

2. Dependência do sistema operacional

Antes de criarmos um novoProcess executando nosso comando shell, precisamos primeiro determinar o sistema operacional no qual nossoJVM está sendo executado.

Isso porque, emWindows, precisamos executar nosso comando como argumento para o shellcmd.exe e em todos os outros sistemas operacionais podemos emitir um shell padrão, chamadosh:

boolean isWindows = System.getProperty("os.name")
  .toLowerCase().startsWith("windows");

3. Entrada e saída

Além disso, ** precisamos de uma maneira de nos conectar aos fluxos de entrada e saída do nosso processo.

Pelo menosthe output must be consumed - caso contrário, nosso processo não retorna com sucesso, em vez disso, ele travará.

Vamos implementar uma classe comumente usada chamadaStreamGobbler que consome umInputStream:

private static class StreamGobbler implements Runnable {
    private InputStream inputStream;
    private Consumer consumer;

    public StreamGobbler(InputStream inputStream, Consumer consumer) {
        this.inputStream = inputStream;
        this.consumer = consumer;
    }

    @Override
    public void run() {
        new BufferedReader(new InputStreamReader(inputStream)).lines()
          .forEach(consumer);
    }
}

NOTE: Esta classe está implementando a interfaceRunnable, o que significa que ela pode ser executada por qualquerExecutor.

4. Runtime.exec()

Uma chamada de método paraRuntime.exec() é uma maneira simples, ainda não customizável, de gerar um novo subprocesso.

No exemplo a seguir, solicitaremos uma lista de diretórios do diretório inicial de um usuário e a imprimiremos no console:

String homeDirectory = System.getProperty("user.home");
Process process;
if (isWindows) {
    process = Runtime.getRuntime()
      .exec(String.format("cmd.exe /c dir %s", homeDirectory));
} else {
    process = Runtime.getRuntime()
      .exec(String.format("sh -c ls %s", homeDirectory));
}
StreamGobbler streamGobbler =
  new StreamGobbler(process.getInputStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
int exitCode = process.waitFor();
assert exitCode == 0;

5. ProcessBuilder

Para a segunda implementação do nosso problema de computação, usaremos umProcessBuilder. É preferível à abordagemRuntime porque podemos personalizar alguns detalhes.

Por exemplo, somos capazes de:

  • mude o diretório de trabalho em que nosso comando shell está rodando usandobuilder.directory()

  • configurar um mapa de valor-chave personalizado como ambiente usandobuilder.environment()

  • redirecionar fluxos de entrada e saída para substituições personalizadas

  • herdar ambos para os fluxos do processoJVM atual usandobuilder.inheritIO()

ProcessBuilder builder = new ProcessBuilder();
if (isWindows) {
    builder.command("cmd.exe", "/c", "dir");
} else {
    builder.command("sh", "-c", "ls");
}
builder.directory(new File(System.getProperty("user.home")));
Process process = builder.start();
StreamGobbler streamGobbler =
  new StreamGobbler(process.getInputStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
int exitCode = process.waitFor();
assert exitCode == 0;

6. Conclusão

Como vimos neste tutorial rápido, podemos executar um comando shell emJava de duas maneiras distintas.

Geralmente, se você está planejando personalizar a execução do processo gerado, por exemplo, para alterar seu diretório de trabalho, você deve considerar o uso de umProcessBuilder.

Como sempre, você encontrará as fonteson GitHub.