2016-07-24 3 views
0

Ich möchte einen beliebigen Bash-Befehl ausführen. Ich habe Command::new gefunden, kann aber keine "komplexen" Befehle wie ls ; sleep 1; ls ausführen. Außerdem, selbst wenn ich dies in ein Bash-Skript einfüge und es ausführe, werde ich nur das Ergebnis am Ende des Skripts haben (wie es im Prozess doc erklärt wird). Ich möchte das Ergebnis erhalten, sobald der Befehl es druckt (und auch Eingaben lesen können), genauso wie wir es in bash machen können.Führen Sie einen beliebigen Bash-Befehl aus, rufen Sie sofort die Ergebnisse von stdout/stderr ab und verwenden Sie stdin

+0

Was meinst du mit „und in der Lage sein Lese auch die Eingabe "? – malbarbo

+0

Ich meine, wenn Sie ein Programm von der Kommandozeile starten: './Myprog ', sehr oft wartet das Programm auf die Eingabe einiger Daten, zum Beispiel, wenn es ein Kommandozeilenspiel ist, kann es eine Nummer fragen. Wenn ich Command :: new() benutze, wird es sofort beendet, wenn es sich zum Beispiel um eine 'read_line' handelt. Keine Zeit, etwas einzugeben. Ich meine, ich möchte wirklich so handeln, als hätte ich das Programm von der Kommandozeile aus ausgeführt. – x4rkz

Antwort

4

Command::new ist zwar der Weg zu gehen, aber es soll ein Programm ausführen. ls ; sleep 1; ls ist kein Programm, es ist Anweisungen für einige Shell. Wenn Sie so etwas ausführen möchten, müssen Sie eine Shell fragen, das für Sie zu interpretieren:

Command::new("/usr/bin/sh").args(&["-c", "ls ; sleep 1; ls"]) 
// your complex command is just an argument for the shell 

die Ausgabe zu erhalten, gibt es zwei Möglichkeiten:

  • die output Verfahren blockiert und gibt die Ausgänge und den Exit-Status des Befehls zurück.
  • die spawn Methode ist nicht blockierend, und gibt einen Handle der Prozess des Kindes enthält stdin, stdout und stderr so können Sie mit dem Kind kommunizieren, und ein wait Methode für sie Ausfahrt sauber zu warten. Hinweis standardmäßig, dass das Kind erbt der übergeordneten Dateideskriptor und Sie könnten Rohre wollen stattdessen einzurichten:

Sie so etwas wie verwenden sollte:

let child = Command::new("/usr/bin/sh") 
       .args(&["-c", "ls sleep 1 ls"]) 
       .stderr(std::process::Stdio::null()) // don't care about stderr 
       .stdout(std::process::Stdio::piped()) // set up stdout so we can read it 
       .stdin(std::process::Stdio::piped()) // set up stdin so we can write on it 
       .spawn().expect("Could not run the command"); // finally run the command 

write_something_on(child.stdin); 
read(child.stdout); 
+0

Danke, ich habe die Zeilen mit 'piped()' oder 'null()' kommentiert, weil ich die Dateideskriptoren der Eltern verwenden möchte. – x4rkz

+1

Da 'Command' dem Builder-Muster folgt, ist es etwas idiomatischer, es so zu strukturieren: https://play.rust-lang.org/?gist=37194d432ecb64c32d5fc5e59937570e&version=stable&backtrace=0 –

+0

@NateMara Eigentlich habe ich ursprünglich https geschrieben: //gist.github.com/2c21ce9e7b919b30cb1444548dc897d9, und war ziemlich überrascht, dass es "& mut self" anstelle von "self" braucht. Wie auch immer, du hast Recht, ich werde meine Antwort bearbeiten, danke. – mcarton

Verwandte Themen