Pertama, saya akan merekomendasikan mengganti baris
Process process = Runtime.getRuntime ().exec ("/bin/bash");
dengan garis
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilder baru di Java 5 dan membuat proses eksternal berjalan lebih mudah. Menurut pendapat saya, peningkatan paling signifikannya Runtime.getRuntime().exec()
adalah memungkinkan Anda untuk mengarahkan kesalahan standar dari proses anak ke dalam keluaran standarnya. Ini berarti Anda hanya memiliki satu InputStream
untuk dibaca. Sebelum ini, Anda perlu memiliki dua Thread terpisah, satu membaca dari stdout
dan satu membaca dari stderr
, untuk menghindari pengisian buffer kesalahan standar sementara buffer keluaran standar kosong (menyebabkan proses anak hang), atau sebaliknya.
Selanjutnya, loop (yang Anda miliki dua)
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
hanya keluar ketika reader
, yang membaca dari keluaran standar proses, mengembalikan akhir file. Ini hanya terjadi ketika bash
proses keluar. Ini tidak akan mengembalikan akhir file jika saat ini tidak ada lagi output dari proses. Sebaliknya, ia akan menunggu baris keluaran berikutnya dari proses dan tidak kembali sampai ia memiliki baris berikutnya ini.
Karena Anda mengirim dua baris input ke proses sebelum mencapai loop ini, loop pertama dari dua loop ini akan hang jika proses belum keluar setelah dua baris input ini. Itu akan duduk di sana menunggu baris lain untuk dibaca, tetapi tidak akan pernah ada baris lain untuk dibaca.
Saya mengkompilasi kode sumber Anda (saya menggunakan Windows saat ini, jadi saya menggantinya /bin/bash
dengan cmd.exe
, tetapi prinsipnya harus sama), dan saya menemukan bahwa:
- setelah mengetik dalam dua baris, output dari dua perintah pertama muncul, tetapi kemudian program hang,
- jika saya mengetikkan, katakan,,,
echo test
dan kemudian exit
, program membuatnya keluar dari loop pertama sejak cmd.exe
proses telah keluar. Program kemudian meminta baris input lain (yang diabaikan), langsung melewati loop kedua karena proses turunan sudah keluar, dan kemudian keluar sendiri.
- jika saya mengetik
exit
dan kemudian echo test
, saya mendapatkan IOException yang mengeluh tentang pipa yang ditutup. Ini sudah biasa - baris pertama input menyebabkan proses keluar, dan tidak ada tempat untuk mengirim baris kedua.
Saya telah melihat trik yang melakukan sesuatu yang mirip dengan apa yang tampaknya Anda inginkan, dalam program yang dulu saya kerjakan. Program ini menyimpan sejumlah shell, menjalankan perintah di dalamnya dan membaca keluaran dari perintah ini. Trik yang digunakan adalah selalu menulis baris 'ajaib' yang menandai akhir keluaran perintah shell, dan menggunakannya untuk menentukan kapan keluaran dari perintah yang dikirim ke shell telah selesai.
Saya mengambil kode Anda dan saya mengganti semuanya setelah baris yang ditetapkan writer
dengan loop berikut:
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;
}
}
Setelah melakukan ini, saya dapat dengan andal menjalankan beberapa perintah dan keluaran dari masing-masing perintah kembali kepada saya secara individual.
Dua echo --EOF--
perintah dalam baris yang dikirim ke shell ada di sana untuk memastikan bahwa keluaran dari perintah diakhiri dengan --EOF--
bahkan akibat kesalahan dari perintah.
Tentu saja, pendekatan ini memiliki keterbatasan. Batasan ini meliputi:
- jika saya memasukkan perintah yang menunggu input pengguna (mis. shell lain), program tampak hang,
- itu mengasumsikan bahwa setiap proses yang dijalankan oleh shell mengakhiri outputnya dengan baris baru,
- itu menjadi sedikit bingung jika perintah yang dijalankan oleh shell kebetulan menulis sebuah baris
--EOF--
.
bash
melaporkan kesalahan sintaks dan keluar jika Anda memasukkan beberapa teks dengan yang tidak cocok )
.
Poin-poin ini mungkin tidak masalah bagi Anda jika apa pun yang Anda pikirkan untuk dijalankan sebagai tugas terjadwal akan dibatasi pada sebuah perintah atau sekumpulan kecil perintah yang tidak akan pernah berperilaku patologis seperti itu.
EDIT : tingkatkan penanganan keluar dan perubahan kecil lainnya setelah menjalankan ini di Linux.