Em várias situações temos a necessidade de executar comandos no terminal através do Java, as mais comuns são para executar algum programa, como abrir o navegar com uma página especifica ou interagir com um serviço, ou até mesmo para rodar algum outro script escrito em outra linguagem.

Isto pode ser feito utilizando o um objeto de Runtime. Vamos a um exemplo simples.

try {
	String comando ="C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe https://www.botecodigital.info";
	Process exec = Runtime.getRuntime().exec( comando );
	
} catch (IOException e) {
	e.printStackTrace();
}

Começamos definindo qual comando iremos executar através do terminal, neste caso iremos executar o navegador chrome, passando como parâmetro para ele a url que desejamos que seja aberta. Colocamos o caminho para o executável do chrome e a url a ser aberta em uma String.

Para executar o comando pegamos um objeto Runtime, que é o objeto que permite ao Java interagir com o ambiente, e chamamos o método exec passando como parâmetro a String com o comando a ser executado. O método exec retorna um objeto Process, que representa o processo do programa que o Java está executando, permitindo assim o seu controle e obtenção de informações sobre ele.

Para executarmos um comando mais típico de terminal, como por exemplo o dir, devemos executá-lo pelo comando cmd passando inclusive o parâmetro /c para informar ao cmd que execute o comando especificado(dir) e finalize. Vamos ver um exemplo.

try {
	Process exec = Runtime.getRuntime().exec( "cmd /C dir" );
	
	InputStream in = exec.getInputStream();
	Scanner scan = new Scanner(in);
	while( scan.hasNext() ) {
		System.out.println( scan.nextLine() );
	}
	
} catch (IOException e) {
	e.printStackTrace();
}

Na linha 2 executamos o comando dir, e seu objeto de processo foi colocado na variável exec. Como queremos ver o retorno deste comando obtemos o objeto InputStream do processo(linha 4), é para ele que a saída do comando será enviada. Criamos um objeto Scanner e fazemos a leitura dele enquanto tiver saída e exibimos cada linha.

Lembrando, este exemplo é só um demonstrativo, não é uma boa ideia realizar a listagem de diretório por terminal quando se é possível fazer isso por Java mesmo, isso deixa seu código dependente o que nunca é uma boa ideia. Só execute pelo terminal quando não é possível fazer por Java mesmo.

Já vimos então como obter a saida de um comando executado através do terminal, e como enviamos entradas para um programa/script que está sendo executado? Vamos a um exemplo bem simples, um pequeno script em python que lê dos valores pelo terminal e exibe a sua soma.

v1 = input('Informe v1: ')
v2 = input('Informe v2: ')

soma = int(v1) + int(v2) 

print( f'SOMA = {soma}')

Para executar este pequeno script e envia para ele os valores que ele irá ler utilizamos o seguinte código.

try {
	Process exec = Runtime.getRuntime().exec( "py soma.py" );
	
	OutputStream out = exec.getOutputStream();
	PrintWriter pw = new PrintWriter( out );
	pw.println( 30 );
	pw.println( 20 );
	pw.flush();
	
	
	InputStream in = exec.getInputStream();
	Scanner scan = new Scanner(in);

	while( scan.hasNext() ) {
		System.out.println( scan.nextLine());
	}
	
} catch (IOException e) {
	e.printStackTrace();
}

Na linha 2 executamos o script através do comando py soma.py. Na linha 4 obtemos o objeto OutputStream do processo, é neste objeto que gravamos nossa entradas dentro do programa/script a ser executado. Para facilitar a escrita dentro do OutputStream criamos um objeto PrintWriter que possui métodos mais amigáveis. Não se esqueça que cada entrada deve finalizar com um nova linha então utilize println ou concatene \n ao final da entrada. E pronto a saída será:

Informe v1: Informe v2: SOMA = 50

Em alguns casos o programa/script que desejamos executar demora bastante tempo para processar e queremos que nosso programa aguarde até o processo seja finalizado para então seguir, seja porque devemos confirmar o resultado do processo ou precisamos de algo que o processo gerou como uma uma imagem, ou vídeo. Para isso podemos utilizar o método waitFor() do objeto Process, que aguarda o processo terminar se necessário. Veja um exemplo.

try {
	Process exec = Runtime.getRuntime().exec( "py programa.py" );
			
	InputStream in = exec.getInputStream();
	Scanner scan = new Scanner(in);

	while( scan.hasNext() ) {
		System.out.println( scan.nextLine());
	}
	
	if( exec.waitFor() == 0 ) {
		System.out.println("programa finalizado");
	}
	
} catch (IOException e) {
	e.printStackTrace();
} catch (InterruptedException e) {
	e.printStackTrace();
}

O método waitFor() retorna um inteiro que é o valor de saída do processo, por convenção 0 significa finalização normal.

Bom e se o comando que estamos executando apresenta algum erro, nos exemplo que vimos ele não seria exibido, podemos fazer isso de forma parecida com a saída normal só trocando o o método getInputStream() por getErrorStream(), veja um exemplo:

try {
	Process exec = Runtime.getRuntime().exec( "py programa_erro.py" );
			
	InputStream in = exec.getErrorStream();
	Scanner scan = new Scanner(in);

	while( scan.hasNext() ) {
		System.out.println( scan.nextLine());
	}
	
} catch (IOException e) {
	e.printStackTrace();
}

Bom era isso, lembrando que ao utilizar o terminal seu código fica dependendo do sistema operacional, o que nem sempre é uma boa ideia então deve ser usado com moderação. Então T+ pessoal.