UPDATE: Este artigo foi substituído pelo meu novo artigo “Java exec com ProcessBuilder e ProcessBuilder”. Enquanto o código Java mostrado neste tutorial funciona em casos simples de “Java exec”, o novo artigo mostra como ler corretamente os fluxos de saída do seu comando do sistema em threads Java, e também como escrever na entrada padrão do seu comando, se necessário.

Feel free to read this article for background/legacy information, but I strongly recommend that you use the source code I’m sharing in my newer “Java exec” article, because it resolve the standard input, output, and error problems that I didn’t handle properly in the code below.

Introduction

I’ve read a much about Java but one of the things I rarely see discussed is how you should go about running external system commands. É claro, você provavelmente não lê muito sobre isso porque isso tira a portabilidade das aplicações Java. Por exemplo, se você escrever uma aplicação Java em um sistema Unix, você pode estar interessado em executar o comando “ps -ef”, e ler a saída do comando. Para sistemas Unix isso é ótimo, mas infelizmente, esse mesmo programa não vai funcionar em um sistema Windows porque o comando ps não está disponível no Windows.

Bem, vamos esquecer a portabilidade para este artigo, e demonstrar um método que pode ser usado para executar comandos de sistema. Recebemos muitos pedidos sobre este tópico, então aqui vai.

Discussão (Execução e Processo em Tempo de Execução)

Executar um comando de sistema é relativamente simples – uma vez que você o tenha visto feito da primeira vez. Ele envolve o uso de duas classes Java, a classe Runtime e a classe Process. Basicamente, você usa o método exec da classe Runtime para executar o comando como um processo separado. Ao invocar o método exec retorna um objeto Processo para administrar o subprocesso. Em seguida, usa-se os métodos getInputStream() e getErrorStream() do objeto Process para ler a saída normal do comando, e a saída de erro do comando. O que você faz com o output do comando executado depende inteiramente de você e da aplicação que você está criando.

(Nota: Há também um método getOutputStream() que você pode usar para escrever no processo, mas nós não vamos cobrir esse método neste artigo. Vamos cobrir isso e algumas outras funcionalidades avançadas num artigo futuro.)

Um exemplo de Java exec

O código mostrado na Lista 1 fornece um exemplo funcional da nossa técnica “Java exec” num ficheiro chamado JavaRunCommand.java.

import java.io.*;public class JavaRunCommand { public static void main(String args) { String s = null; try { // run the Unix "ps -ef" command // using the Runtime exec method: Process p = Runtime.getRuntime().exec("ps -ef"); BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); // read the output from the command System.out.println("Here is the standard output of the command:\n"); while ((s = stdInput.readLine()) != null) { System.out.println(s); } // read any errors from the attempted command System.out.println("Here is the standard error of the command (if any):\n"); while ((s = stdError.readLine()) != null) { System.out.println(s); } System.exit(0); } catch (IOException e) { System.out.println("exception happened - here's what I know: "); e.printStackTrace(); System.exit(-1); } }}

Listing 1 (acima): O ficheiro JavaRunCommand.java mostra como pode correr um comando de sistema externo a partir de um programa Java.

Como funciona o nosso código de execução Java

A primeira coisa que faz é especificar o comando que quer correr fornecendo este comando à classe Runtime. Como você não pode criar sua própria instância da classe Runtime, você primeiro usa o método getRuntime para acessar o ambiente em tempo de execução atual e então invoca o método execut em tempo de execução. Isto retorna um objeto Processo.

Tudo o resto que você fizer envolve métodos do objeto Processo. Neste caso, porque estamos executando o comando “ps -ef” em um sistema Unix, só precisamos ler a saída do comando. Ler o erro padrão provavelmente não é necessário neste caso, mas eu pensei no mínimo que valia a pena mostrar, se não uma boa prática de programação.

Eu converto os fluxos de entrada com o InputStreamReader e BufferedReader para que eu possa usar o método readLine() da classe BufferedReader. Como eu uso estas classes, esta aplicação não compilará corretamente com um compilador JDK 1.0.x antigo (estas classes não estavam disponíveis em 1.0.x).

Baixar o código fonte do exemplo “Java exec”

Posso continuar com este tópico, mas o melhor que eu posso recomendar é que você baixe o código fonte e trabalhe com ele por um tempo. Tente executar comandos diferentes para ver se consegue fazê-los funcionar corretamente, e tente executar um comando que requer entrada (isto será um pouco mais complicado).