Защо изходът от подпроцеса е в грешен ред?

Имам програма на Java, която изпълнява sh в интерактивен режим като подпроцес. Входът се копира от System.in, а изходът се копира в System.out. Всичко работи добре, с изключение на това, че когато изпълнявате команди като pwd в тази интерактивна обвивка, изходът се появява в грешен ред, например:

$ pwd
$ /home/viz/workspace

вместо

$ pwd
/home/viz/workspace
$

Разликата е, че в първия случай подканата $ се отпечатва преди изхода от pwd.

Някакви идеи защо се случва и как да го поправя?

Ето кода:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class StreamCopier implements Runnable {
    private InputStream in;
    private OutputStream out;

    public StreamCopier(InputStream in, OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n;
            byte[] buffer = new byte[4096];
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer, 0, n);
                out.flush();
            }
            out.close();
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

public class Test {
    public static void main(String[] args)
            throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec("sh -i +m");
        Thread outThread = new Thread(new StreamCopier(
                process.getInputStream(), System.out));
        outThread.start();
        Thread errThread = new Thread(new StreamCopier(
                process.getErrorStream(), System.err));
        errThread.start();
        Thread inThread = new Thread(new StreamCopier(
                System.in, process.getOutputStream()));
        inThread.start();
        process.waitFor();
        outThread.join();
        errThread.join();
        inThread.join();
    }
}

person vitaut    schedule 18.11.2010    source източник
comment
Какво се случва, ако стартирате различна обвивка?   -  person dacwe    schedule 18.11.2010
comment
@dacwe: Засега успях да накарам само sh да работи. Опитах bash, но беше спрян при опит за IO. Вероятно се нуждае от други опции (+m не помага).   -  person vitaut    schedule 18.11.2010


Отговори (1)


Тъй като стандартната грешка и стандартният изход отиват към различни нишки, които отпечатват прочетените данни асинхронно. Може да работи, ако пренасочите 2>&1, но не съм сигурен, че ще работи с Runtime.exec (може да причини "файлът не е намерен - 2>&1"). Така че можете да създадете shell скрипт, който извиква sh и пренасочва изхода му, и да извикате този скрипт с помощта на Runtime.exec:

#!/bin/sh
sh -i +m 2>&1

и

Runtime.exec("customsh"); 
person khachik    schedule 18.11.2010
comment
Но както $, така и /home/viz/workspace трябва да се изведат на стандартен изход? (така че няма състезание там..) - person dacwe; 18.11.2010
comment
@dacwe Не. Опитайте от командния ред sh 1>temp.log и след това въведете pwd. Ще видите подканата на командния ред, но не и pwd изхода, той ще отиде на temp.log. - person khachik; 18.11.2010
comment
хубаво! Тогава има решение на vitaut! - person dacwe; 18.11.2010