Trước hết, tôi muốn giới thiệu thay thế dòng
Process process = Runtime.getRuntime().exec ("/bin/bash");
với các dòng
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilder là mới trong Java 5 và làm cho quá trình hoạt động bên ngoài dễ dàng hơn. Theo tôi, cải tiến quan trọng nhất của nó trên Runtime.getRuntime().exec()
là nó cho phép bạn chuyển hướng lỗi tiêu chuẩn của tiến trình con vào đầu ra tiêu chuẩn của nó. Điều này có nghĩa là bạn chỉ có một số InputStream
để đọc. Trước đó, bạn cần có hai Chủ đề riêng biệt, một số đọc từ stdout
và một đọc từ stderr
, để tránh lỗi đệm chuẩn trong khi bộ đệm đầu ra tiêu chuẩn trống (gây ra quá trình con treo), hoặc ngược lại.
Tiếp theo, các vòng (trong đó bạn có hai)
while ((line = reader.readLine()) != null) {
System.out.println ("Stdout: " + line);
}
chỉ thoát khi reader
, mà đọc từ đầu ra tiêu chuẩn của quá trình, trả end-of-file. Điều này chỉ xảy ra khi quá trình thoát. Nó sẽ không trả lại kết thúc của tập tin nếu có xảy ra hiện nay để không có đầu ra nhiều hơn từ quá trình này. Thay vào đó, nó sẽ chờ cho dòng đầu ra tiếp theo từ quá trình và không trả lại cho đến khi nó có dòng tiếp theo này.
Vì bạn đang gửi hai dòng đầu vào cho quy trình trước khi tiếp cận vòng lặp này, đầu tiên của hai vòng này sẽ treo nếu quá trình không thoát sau hai dòng đầu vào này. Nó sẽ ngồi đó chờ đợi một dòng khác để đọc, nhưng sẽ không bao giờ có một dòng khác để đọc.
tôi biên soạn mã nguồn của bạn (Tôi đang trên Windows vào lúc này, vì vậy tôi thay /bin/bash
với cmd.exe
, nhưng các nguyên tắc cần được như vậy), và tôi thấy rằng:
- sau khi gõ vào hai dòng, đầu ra từ hai lệnh đầu tiên xuất hiện, nhưng sau đó chương trình bị treo,
- nếu tôi nhập, giả sử,
echo test
và sau đó exit
, chương trình sẽ thoát khỏi vòng đầu tiên kể từ khi quá trình cmd.exe
đã thoát. Chương trình sau đó yêu cầu một dòng đầu vào khác (bị bỏ qua), bỏ qua vòng lặp thứ hai vì quá trình con đã thoát rồi thoát ra khỏi chính nó.
- nếu tôi nhập
exit
và sau đó echo test
, tôi nhận được một IOException phàn nàn về một đường ống đang bị đóng. Điều này được mong đợi - dòng đầu vào đầu tiên đã khiến quá trình thoát ra và không có nơi nào để gửi dòng thứ hai.
Tôi đã thấy một mẹo làm điều gì đó tương tự như những gì bạn muốn, trong một chương trình tôi từng làm việc. Chương trình này được lưu giữ xung quanh một số shell, chạy các lệnh trong chúng và đọc đầu ra từ các lệnh này. Bí quyết được sử dụng là luôn luôn viết ra một dòng 'ma thuật' đánh dấu kết thúc của đầu ra của lệnh shell, và sử dụng nó để xác định khi nào đầu ra từ lệnh được gửi đến trình bao đã kết thúc.
tôi lấy mã của bạn và tôi đã thay thế tất cả mọi thứ sau khi dòng đó gán cho writer
với vòng lặp sau:
while (scan.hasNext()) {
String input = scan.nextLine();
if (input.trim().equals("exit")) {
// Putting 'exit' amongst the echo --EOF--s below doesn't work.
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;
}
}
Sau khi làm điều này, tôi có thể chắc chắn chạy một vài lệnh và có đầu ra từ mỗi trở lại cho riêng tôi.
Hai lệnh echo --EOF--
trong dòng được gửi đến trình bao ở đó để đảm bảo rằng đầu ra từ lệnh được kết thúc bằng --EOF--
ngay cả trong kết quả của lỗi từ lệnh.
Tất nhiên, phương pháp này có những hạn chế của nó. Những hạn chế này bao gồm:
- nếu tôi nhập một lệnh mà chờ đợi cho người dùng nhập vào (ví dụ vỏ khác), chương trình xuất hiện để treo,
- Nó giả định rằng mỗi quá trình chạy bằng vỏ kết thúc sản lượng của nó với một dòng mới ,
- sẽ hơi bị nhầm lẫn nếu lệnh được chạy bởi vỏ xảy ra để viết ra một dòng
--EOF--
.
bash
báo cáo lỗi cú pháp và thoát ra nếu bạn nhập một số văn bản với một chưa từng có )
.
Những điểm này có thể không quan trọng đối với bạn nếu bạn đang nghĩ đến việc chạy tác vụ được lên lịch sẽ bị giới hạn trong lệnh hoặc tập lệnh nhỏ sẽ không bao giờ hoạt động theo cách bệnh lý như vậy.
EDIT: cải thiện xử lý thoát và các thay đổi nhỏ khác sau khi chạy trên Linux.
"Đường ống bị hỏng" có thể có nghĩa là quy trình con đã thoát. Chưa xem hết phần còn lại của mã của bạn để xem các vấn đề khác là gì. – vanza
sử dụng chủ đề riêng biệt, nó sẽ hoạt động tốt – Johnydep