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.