如何在子进程Shell中执行命令?Rust能否操控新Shell执行命令?
How to Execute Commands in a Shell Spawned as a Subprocess (Rust Specific)
Great question! Let's break this down clearly to cover both parts of your query:
1. General Ways to Run Commands in a Child Shell
There are two primary patterns here:
- Single one-off command: Pass the command directly to the shell using the
-cflag. This spawns the shell, runs your command, then exits immediately. - Persistent interactive session: Spawn a long-running shell process, then send commands to its standard input stream and read results from its output/error streams.
2. Executing Commands in Your Spawned sh Subprocess with Rust
Absolutely! The trick is to redirect the shell's input/output/error streams so your Rust program can communicate with it. Here's a practical example that shows how to do this:
use std::io::{self, Write}; use std::process::{Command, Stdio}; fn main() -> io::Result<()> { // Spawn a persistent sh shell with piped streams for interaction let mut child = Command::new("sh") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn()?; // Grab handles to the shell's input and output channels let mut stdin = child.stdin.take().expect("Couldn't access shell's stdin"); let mut stdout = child.stdout.take().expect("Couldn't access shell's stdout"); // Send a command to the shell (don't forget the newline—shells need it to execute!) writeln!(stdin, "echo 'Hi from the child shell!'")?; // Flush the buffer to make sure the command is sent right away stdin.flush()?; // Read and print the shell's output let mut output = String::new(); stdout.read_to_string(&mut output)?; println!("Shell output:\n{}", output); // Send another command if you want writeln!(stdin, "pwd")?; stdin.flush()?; output.clear(); stdout.read_to_string(&mut output)?; println!("Second command output:\n{}", output); // Terminate the shell cleanly writeln!(stdin, "exit")?; stdin.flush()?; // Wait for the shell process to finish and check its exit status let exit_status = child.wait()?; println!("Shell exited with status: {}", exit_status); Ok(()) }
Important Details:
Stdio::piped(): This creates communication pipes between your Rust program and the child shell, enabling two-way interaction.- Newlines: Shells require a newline character to recognize the end of a command—use
writeln!or append\nto your command strings. - Flushing stdin: The
flush()call ensures your command isn't stuck in a buffer and gets sent to the shell immediately. - Error handling: The example uses
?for error propagation andexpect()for simplicity, but in production code, you’ll want to handle errors gracefully withmatchorif letstatements.
If you only need to run a single command (no persistent shell), a simpler approach works too:
use std::process::Command; fn main() { let output = Command::new("sh") .arg("-c") .arg("echo 'Quick one-off command!' && ls -la") .output() .expect("Failed to run command"); println!("Output:\n{}", String::from_utf8_lossy(&output.stdout)); if !output.stderr.is_empty() { println!("Errors:\n{}", String::from_utf8_lossy(&output.stderr)); } }
This spawns the shell, runs your command(s), collects all output, and exits—no ongoing interaction required.
内容的提问来源于stack exchange,提问作者Harshit
相关产品推荐
相关产品推荐

