Como executar um comando Shell em Java

Overview

Com este tutorial vamos ilustrar as duas formas de executar um comando Shell a partir do código Java.

A primeira é usar a classe Runtime e chamar seu método exec.

A segunda e mais customizável forma, será criar e usar uma instância ProcessBuilder.

Operating System Dependency

Antes de criarmos um novo Processo executando nosso comando shell, precisamos primeiro determinar o sistema operacional no qual nossa JVM está rodando.

Isso porque, no Windows, precisamos rodar nosso comando como argumento para o cmd.exe shell e em todos os outros sistemas operacionais podemos emitir um shell padrão, chamado sh:

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

Input and Output

Outras vezes precisamos de uma maneira de se conectar aos fluxos de entrada e saída do nosso processo.

No mínimo a saída deve ser consumida – caso contrário o nosso processo não retorna com sucesso, em vez disso ele irá pendurar.

Vamos implementar uma classe comumente usada chamada StreamGobbler que consome um InputStream:

private static class StreamGobbler implements Runnable { private InputStream inputStream; private Consumer<String> consumer; public StreamGobbler(InputStream inputStream, Consumer<String> 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 interface Runnable, o que significa que ela poderia ser executada por qualquer Executor.

Runtime.exec()

Uma chamada ao método Runtime.exec() é uma forma simples, ainda não personalizável, de criar um novo subprocesso.

No exemplo a seguir vamos solicitar uma listagem de diretórios de um diretório de usuários e imprimi-la para o 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;

ProcessBuilder

Para a segunda implementação do nosso problema de computação, estaremos usando um ProcessBuilder. Isto é preferível à abordagem de Tempo de Execução porque somos capazes de personalizar alguns detalhes.

Por exemplo, somos capazes de:

  • alterar o directório de trabalho em que o nosso comando shell está a correr utilizando o construtor.directory()
  • configurar um mapa de valores chave personalizado como ambiente usando o builder.environment()
  • crever fluxos de entrada e saída para substituições personalizadas
  • inherit ambos para os fluxos do processo JVM atual usando o builder.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;

Conclusion

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

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

Deixe uma resposta

O seu endereço de email não será publicado.