Eu tenho o seguinte exemplo de código abaixo. Por meio do qual você pode inserir um comando no shell bash, ou seja, echo test
e ter o resultado ecoado de volta. No entanto, após a primeira leitura. Outros fluxos de saída não funcionam?
Por que isso ou estou fazendo algo errado? Meu objetivo final é criar uma tarefa agendada Threaded que executa um comando periodicamente para / bash para que OutputStream
e InputStream
tenha que trabalhar em conjunto e não parar de funcionar. Eu também tenho experimentado o erro java.io.IOException: Broken pipe
alguma idéia?
Obrigado.
String line;
Scanner scan = new Scanner(System.in);
Process process = Runtime.getRuntime ().exec ("/bin/bash");
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
String input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.close();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
Respostas:
Em primeiro lugar, eu recomendaria substituir a linha
com as linhas
ProcessBuilder é novo no Java 5 e torna a execução de processos externos mais fácil. Em minha opinião, sua melhoria mais significativa
Runtime.getRuntime().exec()
é que ele permite redirecionar o erro padrão do processo filho para sua saída padrão. Isso significa que você só tem umInputStream
para ler. Antes disso, você precisava ter dois Threads separados, um lendostdout
e outro lendostderr
, para evitar o preenchimento do buffer de erro padrão enquanto o buffer de saída padrão estava vazio (fazendo com que o processo filho travasse) ou vice-versa.Em seguida, os loops (dos quais você tem dois)
só sai quando o
reader
, que lê a saída padrão do processo, retorna o fim do arquivo. Isso só acontece quando obash
processo é encerrado. Ele não retornará o fim do arquivo se no momento não houver mais saída do processo. Em vez disso, ele aguardará a próxima linha de saída do processo e não retornará até que tenha a próxima linha.Como você está enviando duas linhas de entrada para o processo antes de chegar a este loop, o primeiro desses dois loops irá travar se o processo não tiver saído após essas duas linhas de entrada. Ele ficará parado esperando que outra linha seja lida, mas nunca haverá outra linha para ser lida.
Compilei seu código-fonte (estou no Windows no momento, então substituí
/bin/bash
porcmd.exe
, mas os princípios devem ser os mesmos) e descobri que:echo test
e, em seguidaexit
, o programa sairá do primeiro loop desde que ocmd.exe
processo foi encerrado. O programa então pede outra linha de entrada (que é ignorada), pula direto sobre o segundo loop, uma vez que o processo filho já saiu, e então sai sozinho.exit
eecho test
, em seguida , obtenho uma IOException reclamando sobre um tubo sendo fechado. Isso era esperado - a primeira linha de entrada fez com que o processo fosse encerrado e não há para onde enviar a segunda linha.Eu vi um truque que faz algo semelhante ao que você parece querer, em um programa que eu costumava trabalhar. Este programa mantinha vários shells, executava comandos neles e lia a saída desses comandos. O truque usado era sempre escrever uma linha 'mágica' que marca o fim da saída do comando shell e usá-la para determinar quando a saída do comando enviado ao shell havia terminado.
Peguei seu código e substituí tudo após a linha que atribui a
writer
pelo seguinte loop:Depois de fazer isso, eu poderia executar alguns comandos de forma confiável e ter a saída de cada um voltando para mim individualmente.
Os dois
echo --EOF--
comandos na linha enviada para o shell estão lá para garantir que a saída do comando seja encerrada--EOF--
mesmo em caso de erro do comando.Claro, essa abordagem tem suas limitações. Essas limitações incluem:
--EOF--
.bash
relata um erro de sintaxe e sai se você inserir algum texto com um não correspondente)
.Esses pontos podem não importar para você se tudo o que você está pensando em executar como uma tarefa agendada for restrito a um comando ou um pequeno conjunto de comandos que nunca se comportarão de maneira tão patológica.
EDIT : melhore o tratamento de saída e outras pequenas alterações após a execução no Linux.
fonte
Eu acho que você pode usar thread como demon-thread para ler sua entrada e seu leitor de saída já estará em loop while no thread principal para que você possa ler e escrever ao mesmo tempo. Você pode modificar seu programa assim:
e você pode ler será o mesmo que acima, ou seja
faça seu escritor como final, caso contrário, ele não poderá ser acessado pela classe interna.
fonte
Você tem
writer.close();
em seu código. Assim, o bash recebe EOFstdin
e sai. Então você começaBroken pipe
ao tentar ler dostdout
bash extinto.fonte