İlk olarak, satırı değiştirmenizi tavsiye ederim
Process process = Runtime.getRuntime ().exec ("/bin/bash");
çizgilerle
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilder Java 5'te yenidir ve harici işlemlerin çalıştırılmasını kolaylaştırır. Kanımca, en önemli gelişmesi Runtime.getRuntime().exec()
, alt sürecin standart hatasını standart çıktısına yeniden yönlendirmenize izin vermesidir. Bu InputStream
, okuyabileceğiniz yalnızca bir tane var demektir . Bundan önce , standart çıktı arabelleği boşken (alt işlemin askıda kalmasına neden olur) standart hata arabelleği doldurmasını önlemek için stdout
biri okuma diğeri de okuma olmak üzere iki ayrı İş Parçacığına sahip olmanız gerekiyordu stderr
.
Ardından, döngüler (bunlardan iki tane var)
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
yalnızca reader
işlemin standart çıktısını okuyan dosya sonu döndürdüğünde çık . Bu yalnızca bash
işlem çıktığı zaman olur . Şu anda işlemden daha fazla çıktı alınmaması durumunda dosya sonu dönmeyecektir. Bunun yerine, işlemden sonraki çıktı satırını bekleyecek ve bu sonraki satırı alana kadar geri dönmeyecektir.
Bu döngüye ulaşmadan önce işleme iki satır girdi gönderdiğiniz için, bu iki satırdan sonra işlem çıkmadıysa bu iki döngüden ilki askıda kalacaktır. Orada oturacak başka bir satırın okunmasını bekleyecek, ancak okuyacağı başka bir satır asla olmayacak.
Ben kaynak kodu (yerime başkasının yüzden, şu anda Windows üzerinde olduğum derlenmiş /bin/bash
ile cmd.exe
, ancak prensipler aynı olmalıdır) ve bunu buldum:
- iki satır yazdıktan sonra, ilk iki komutun çıktısı görünür, ancak daha sonra program kilitlenir,
- eğer yazarsam, diyelim
echo test
ve sonra exit
, program cmd.exe
işlemden çıktığından beri ilk döngüden çıkarır . Program daha sonra başka bir girdi satırı ister (ki bu yok sayılır), alt süreç zaten çıktığı için ikinci döngü üzerinden düz bir şekilde atlar ve sonra kendisinden çıkar.
- Ben yazarsanız
exit
ve sonra echo test
, bir IOException bir boru kapatılıyor şikayet olsun. Bu beklenen bir şeydir - ilk girdi satırı işlemin çıkmasına neden oldu ve ikinci satırı gönderecek yer yok.
Eskiden üzerinde çalıştığım bir programda, sizin istediğiniz gibi görünen şeye benzer bir şey yapan bir numara gördüm. Bu program bir dizi mermiyi tuttu, içlerinde komutlar çalıştırdı ve bu komutların çıktılarını okudu. Kullanılan hile, her zaman kabuk komutunun çıktısının sonunu işaretleyen 'sihirli' bir satır yazmak ve bunu, kabuğa gönderilen komutun çıktısının ne zaman bittiğini belirlemek için kullanmaktı.
Kodunuzu aldım ve atanan satırdan sonraki her şeyi writer
aşağıdaki döngü ile değiştirdim:
while (scan.hasNext()) {
String input = scan.nextLine();
if (input.trim().equals("exit")) {
writer.write("exit\n");
} else {
writer.write("((" + input + ") && echo --EOF--) || echo --EOF--\n");
}
writer.flush();
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
System.out.println ("Stdout: " + line);
line = reader.readLine();
}
if (line == null) {
break;
}
}
Bunu yaptıktan sonra, birkaç komutu güvenilir bir şekilde çalıştırabilir ve her birinin çıktısının bana ayrı ayrı gelmesini sağlayabilirim.
echo --EOF--
Kabuğa gönderilen satırdaki iki komut, komuttan --EOF--
gelen bir hata sonucunda bile komuttan çıkışın sonlandırılmasını sağlamak için oradadır .
Elbette bu yaklaşımın sınırlamaları vardır. Bu sınırlamalar şunları içerir:
- Kullanıcı girdisini bekleyen bir komut girersem (örneğin başka bir kabuk), program kilitleniyor gibi görünür,
- Kabuk tarafından çalıştırılan her işlemin çıktısını bir satırsonu ile bitirdiğini varsayar,
- Kabuk tarafından çalıştırılan komut bir satır yazarsa biraz karışır
--EOF--
.
bash
bir sözdizimi hatası bildirir ve eşleşmeyen bir metin girerseniz çıkar )
.
Zamanlanmış bir görev olarak çalıştırmayı düşündüğünüz her ne olursa olsun, bir komutla veya asla bu tür patolojik şekillerde davranmayacak küçük bir komutlar setiyle sınırlandırılacaksa, bu noktalar sizin için önemli olmayabilir.
DÜZENLEME : çıkış işlemeyi ve bunu Linux'ta çalıştırdıktan sonra diğer küçük değişiklikleri iyileştirin.