Translate

sexta-feira, 1 de fevereiro de 2013

Executar linha de comando com Java

Em alguns momentos na programação, executar linhas de comandos em algum S.O. (Sistema Operacional) é uma ótima opção para interagir com seu sistema de arquivos, programas e recursos consagrados de forma direta.

Mas como fazer isso através da linguagem de programação Java?

Como uma forma segura e única para executar comando direto de um Sistema Operacional, a classe LineCommand foi criada com a função execCommand síncrona e estática.

Classe LineCommand

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class LineCommand {

    public synchronized static String execCommand(final String commandLine) throws IOException {

        boolean success = false;
        String result;

        Process p;
        BufferedReader input;
        StringBuffer cmdOut = new StringBuffer();
        String lineOut = null;
        int numberOfOutline = 0;

        try {

            p = Runtime.getRuntime().exec(commandLine);

            input = new BufferedReader(new InputStreamReader(p.getInputStream()));

            while ((lineOut = input.readLine()) != null) {
                if (numberOfOutline > 0) {
                    cmdOut.append("\n");
                }
                cmdOut.append(lineOut);
                numberOfOutline++;
            }

            input.close();
          
            result = cmdOut.toString();

            success = (p.waitFor() == 0);
          
        } catch (IOException e) {
            result = String.format("Falha ao executar comando %s. Erro: %s", commandLine, e.toString());
        } catch (InterruptedException e) {
            result = String.format("Falha ao executar comando %s. Erro: %s", commandLine, e.toString());
        }

        // Se não executou com sucesso, lança a falha
        if (!success) {
            throw new IOException(result);
        }

        return result;

    }

}


Um programador soberbo pode perguntar: Para que tanto código?

É muitos simples,  a função execCommand:
  1. tem como parâmetro uma String para você informar a linha de comando;
  2. a função é estática para permitir a chamada direta a partir de sua classe LineCommand;
  3. é síncrona para impedir muitas interações paralelas com o S.O. caso o programador faça uma chamada recursiva acidental;
  4. retorna uma String com o resultado fiél da execução;
  5. tem tratamento de exceção para caso de erro nativo no comando, converte o erro para uma exceção Java para o programador capturar e tratar;
  6. tem captura de erro lançado pela execução de comando incorreto.
Vamos realizar alguns testes baseado em S.O. Windows.

Testando

O código a seguir testa três situações: uma situação correta de comando, outra situação de comando correto com parâmetro inválido e por último, é executado um comando inválido. Você perceberá que todas estas situações serão compreendidas pela função.

    public static void main(String[] args) {

        String result = null;

        // Teste com comando correto
        try {
            result = LineCommand.execCommand("cmd /C dir c:");
            System.out.println(result);
        } catch (IOException e) {
            System.err.println(e.getMessage());;
        }

        // Teste com comando correto e parâmetro incorreto
        try {
            result = LineCommand.execCommand("cmd /C dir ccc:");
            System.out.println(result);
        } catch (IOException e) {
            System.err.println(e.getMessage());;
        }

        // Teste com comando desconhecido
        try {
            result = LineCommand.execCommand("go to");
            System.out.println(result);
        } catch (IOException e) {
            System.err.println(e.getMessage());;
        }
      
    }


Resultado

Após a execução, o resultado a seguir será obtido.

Teste com comando correto:
 O volume na unidade C nÆo tem nome.
 O N£mero de S‚rie do Volume ‚ 54C4-76F5

 Pasta de C:\Users\teste\workspace\DNPark

09/11/2012  17:27    <DIR>          .
09/11/2012  17:27    <DIR>          ..
13/10/2012  17:45             1.212 .classpath
28/01/2012  12:23               382 .project
13/10/2012  15:43    <DIR>          .settings
01/02/2013  00:28    <DIR>          build
20/11/2010  21:34               332 build.properties
14/10/2012  13:02             4.090 build_dnpark.xml
12/10/2012  19:50           233.857 DNPark_Nettyc.rar
09/11/2012  17:27    <DIR>          DNPark_Release
09/11/2012  17:27         4.390.741 DNPark_Release.zip
04/04/2012  12:15         2.718.075 DNPark_Release_2_1_0.rar
13/10/2012  22:27         4.228.801 DNPark_Release_2_2_0.rar
14/10/2012  20:20         4.235.275 DNPark_Release_2_3_0.rar
05/11/2012  18:30         4.240.128 DNPark_Release_2_4_0.rar
08/11/2012  12:48         4.240.244 DNPark_Release_2_4_1.rar
12/10/2012  10:57           235.820 DNPark_VersaoComandos_Modem_Tunelador.rar
12/10/2012  18:03           228.914 DNPrk_Antes_NETTY.rar
08/11/2012  12:49             7.212 HistoricoDeVersao.txt
13/10/2012  17:45    <DIR>          lib
11/01/2011  16:26                59 netpathw.bat
10/01/2011  11:49           262.427 NetPath_Kit.rar
13/10/2012  15:45    <DIR>          src
13/10/2012  15:43    <DIR>          subproject
13/10/2012  15:44    <DIR>          wrapper_WinNT
06/04/2011  12:22           141.017 wrapper_WinNT.rar
              17 arquivo(s)     25.168.586 bytes
               9 pasta(s)   18.772.152.320 bytes dispon¡veis


Teste com comando correto e parâmetro incorreto:
 O volume na unidade C nÆo tem nome.
 O N£mero de S‚rie do Volume ‚ 54C4-76F5

 Pasta de C:\Users\teste\workspace\DNPark



Teste com comando desconhecido:
Falha ao executar comando go to. Erro: java.io.IOException: Cannot run program "go": CreateProcess error=2, O sistema não pode encontrar o arquivo especificado


 Até breve.

4 comentários:

  1. olá gostaria de saber como eu faço para executar mais de um comando por exemplo
    eu quero entrar no c: depois cd \pasta e executar um programa .exe

    vc pode me ajudar?

    ResponderExcluir
  2. Cria um arquivo BAT e se tiver algum parâmetro variável, você deve utilizar o %1 %2 ... para passar para dentro do BAT quando ele executar.

    Pesquisa como escrever um BAT e passar parâmetros porque isso tem aos montes na Internet.

    Qualquer problema, entra em contato.

    ResponderExcluir
  3. Boa tarde, precisava de algo muito semelhante a isso.

    Mas no meu caso, eu tenho uma sequencia de comandos, onde o primeiro deles, é uma conexao SSH -S none admin@ipdodispositivo.
    Ai após esse comando preciso enviar um novo comando com o PASSWORD.

    Quando faço o mesmo procedimento direto no prompt, ele automaticamente pede a senha.

    Como fazer isso no java ?

    ResponderExcluir