Chcę być w stanie użyć Rust do odrodzenia powłoki podrzędnej, a następnie wielokrotnie przekazywać jej dowolne polecenia i przetwarzać ich wyniki. Znalazłem mnóstwo przykładów online pokazujących, jak przekazać pojedyncze polecenie i otrzymać jego pojedyncze wyjście, ale nie mogę tego robić wielokrotnie.Nie można potokować do lub od spawned procesu potomnego więcej niż raz
Na przykład poniższy kod zawiesza się w wierszu po komentarzu. (Wyobrażam sobie może read_to_string()
blokuje dopóki nie otrzyma stdout od procesu potomnego, ale jeśli tak nie rozumiem dlaczego, że produkcja nie jest w przygotowaniu ..)
let mut child_shell = match Command::new("/bin/bash")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
{
Err(why) => panic!("couldn't spawn child_shell: {}", Error::description(&why)),
Ok(process) => process,
};
loop {
{
match child_shell.stdin.as_mut().unwrap().write("ls".as_bytes()) {
Err(why) => panic!(
"couldn't send command to child shell: {}",
Error::description(&why)
),
Ok(_) => println!("sent command to child shell"),
}
}
{
let mut s = String::new();
// ↓ hangs on this line ↓
match child_shell.stdout.as_mut().unwrap().read_to_string(&mut s) {
Err(why) => panic!("couldn't read bash stdout: {}", Error::description(&why)),
Ok(_) => print!("bash responded with:\n{}", s),
}
}
}
jestem początkujący w Rust i I uważam, że problemem jest moje ograniczone zrozumienie reguł sprawdzania i odnoszenia pożyczek, ponieważ powyższe działa dobrze (dla pojedynczej iteracji), jeśli usunę instrukcję pętli z kodu i zmienię odniesienia do początków struktury std::process::Child
na niezmienne; na przykład z tego:
child_shell.stdin.as_mut().unwrap().write("ls".as_bytes())
do tego:
child_shell.stdin.unwrap().write("ls".as_bytes())
Oczywiście wielokrotnie uruchomiony ls
nie jest mój ostateczny cel, i wiem, że mogę po prostu napisać skrypt, a potem mieć Rust wielokrotnie uruchom go - ale (oprócz celu, aby dowiedzieć się więcej o Rust!), jest to coś, co muszę zrobić, przynajmniej w zasadzie, dla bardziej skomplikowanego projektu (z czego jestem zadowolony, jeśli może udowadniają, że są odpowiednie dla jakichkolwiek rozwiązań, ale prawdopodobnie sposób, poza zakresem tego pytania!)
Na koniec, jeśli okaże się, że nie można w ten sposób użyć skorupy podrzędnej, mimo to chciałbym nauczyć się, jak powtarzać/ciągnąć rury do i od zarodkowanego procesu, wykonując inne arbitralne polecenie, ponieważ ja nie udało się znaleźć żadnych informacji w dokumentacji Rust, samouczkach ani w Stack Overflow.
Dziękuję bardzo! Wszystkie naprawdę przydatne porady i obserwacje. Jeśli chodzi o ustalenie, kiedy przerwać czytanie z 'BufReadera', to dlaczego próbuje on po prostu wywołać' child_out.lines(). Count() 'lub' dla l in child_out.lines() 'w pętli daje mi błąd "użycia przeniesionej wartości: child_out"? Dlaczego mogę zapytać 'BufReadera' o jedną linię, ale nie dla wszystkich? Czy nie rozumiem, jak działają tutaj iteratory? – John
@John nie jak działają iteratory, ale jak działa parametr 'self' dla tych metod. Sprawdź ['count'] (http://doc.rust-lang.org/std/iter/trait.Iterator.html#method.count), aby zobaczyć, że bierze on' self' według wartości, która zużywa podstawowy iterator , tak samo jak ['lines'] (http://doc.rust-lang.org/std/io/trait.BufRead.html#method.lines). Wywołanie 'count' nie ma sensu, ponieważ trzeba by przeczytać * wszystkie * dane wyjściowe procesu, aby uzyskać liczbę, do której wszystkie dane zostałyby wyrzucone. – Shepmaster