@@ -49,11 +49,16 @@ use std::process::{Command, Stdio};
4949/// 3. Call `.output()` to execute the child and obtain its `Output`.
5050/// 4. Convert the `stdout` field (a `Vec<u8>`) into a `String`.
5151pub fn run_command ( program : & str , args : & [ & str ] ) -> String {
52- // TODO: Use Command::new to create process
53- // TODO: Set stdout to Stdio::piped()
54- // TODO: Execute with .output() and get output
55- // TODO: Convert stdout to String and return
56- todo ! ( )
52+ // Use Command::new to create process
53+ // Set stdout to Stdio::piped()
54+ // Execute with .output() and get output
55+ let cmd = Command :: new ( program) . args ( args) . output ( ) . unwrap ( ) ;
56+ if !cmd. status . success ( ) {
57+ // Convert stdout to String and return
58+ String :: from_utf8_lossy ( & cmd. stderr ) . to_string ( )
59+ } else {
60+ String :: from_utf8_lossy ( & cmd. stdout ) . to_string ( )
61+ }
5762}
5863
5964/// Write data to child process (cat) stdin via pipe and read its stdout output.
@@ -84,12 +89,19 @@ pub fn run_command(program: &str, args: &[&str]) -> String {
8489/// 5. Read the child's stdout (`child.stdout.take().unwrap().read_to_string(...)`).
8590/// 6. Wait for the child to exit with `.wait()` (or rely on drop‑wait).
8691pub fn pipe_through_cat ( input : & str ) -> String {
87- // TODO: Create "cat" command, set stdin and stdout to piped
88- // TODO: Spawn process
89- // TODO: Write input to child process stdin
90- // TODO: Drop stdin to close pipe (otherwise cat won't exit)
91- // TODO: Read output from child process stdout
92- todo ! ( )
92+ // Create "cat" command, set stdin and stdout to piped
93+ // 创建 cat 命令,并将标准输入(stdin)和标准输出(stdout)设置为管道模式
94+ // Spawn process 启动(创建)子进程
95+ // Write input to child process stdin 将输入数据写入子进程的标准输入(stdin)
96+ // Drop stdin to close pipe (otherwise cat won't exit) 释放(drop)stdin 以关闭管道(否则 cat 不会退出)
97+ // Read output from child process stdout 从子进程的标准输出(stdout)读取输出数据
98+ let mut child = Command :: new ( "cat" ) . stdin ( Stdio :: piped ( ) ) . stdout ( Stdio :: piped ( ) ) . spawn ( ) . unwrap ( ) ;
99+ let mut stdin = child. stdin . unwrap ( ) ;
100+ stdin. write_all ( input. as_bytes ( ) ) . unwrap ( ) ;
101+ drop ( stdin) ;
102+ let mut buffer = String :: new ( ) ;
103+ child. stdout . take ( ) . unwrap ( ) . read_to_string ( & mut buffer) . unwrap ( ) ;
104+ buffer
93105}
94106
95107/// Get child process exit code.
@@ -107,10 +119,11 @@ pub fn pipe_through_cat(input: &str) -> String {
107119/// 3. Use `.code()` to get the exit code as `Option<i32>`.
108120/// 4. If the child terminated normally, return the exit code; otherwise return a default.
109121pub fn get_exit_code ( command : & str ) -> i32 {
110- // TODO: Use Command::new("sh").args(["-c", command])
111- // TODO: Execute and get status
112- // TODO: Return exit code
113- todo ! ( )
122+ // Use Command::new("sh").args(["-c", command])
123+ // Execute and get status
124+ let status = Command :: new ( "sh" ) . args ( [ "-c" , command] ) . status ( ) . unwrap ( ) ;
125+ // Return exit code
126+ status. code ( ) . unwrap ( )
114127}
115128
116129/// Execute the given shell command and return its stdout output as a `Result`.
@@ -133,11 +146,19 @@ pub fn get_exit_code(command: &str) -> i32 {
133146/// 3. Call `.output()` and propagate any `io::Error`.
134147/// 4. Convert `stdout` to `String` with `String::from_utf8`; if that fails, map to an `io::Error`.
135148pub fn run_command_with_result ( program : & str , args : & [ & str ] ) -> io:: Result < String > {
136- // TODO: Use Command::new to create process
137- // TODO: Set stdout to Stdio::piped()
138- // TODO: Execute with .output() and handle Result
139- // TODO: Convert stdout to String with from_utf8, mapping errors to io::Error
140- todo ! ( )
149+ // Use Command::new to create process
150+ // Set stdout to Stdio::piped()
151+ // Execute with .output() and handle Result
152+ // Convert stdout to String with from_utf8, mapping errors to io::Error
153+ let result = Command :: new ( program) . args ( args) . stdout ( Stdio :: piped ( ) ) . output ( ) ;
154+ if result. is_ok ( ) {
155+ let output = result. unwrap ( ) ;
156+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
157+ Ok ( stdout. to_string ( ) )
158+ } else {
159+ Err ( result. unwrap_err ( ) )
160+ }
161+
141162}
142163
143164/// Interact with `grep` via bidirectional pipes, filtering lines that contain a pattern.
@@ -161,13 +182,34 @@ pub fn run_command_with_result(program: &str, args: &[&str]) -> io::Result<Strin
161182/// 7. Return the concatenated matching lines as a single `String`.
162183///
163184pub fn pipe_through_grep ( pattern : & str , input : & str ) -> String {
164- // TODO: Create "grep" command with pattern, set stdin and stdout to piped
165- // TODO: Spawn process
166- // TODO: Write input lines to child stdin
167- // TODO: Drop stdin to close pipe
168- // TODO: Read output from child stdout line by line
169- // TODO: Collect and return matching lines
170- todo ! ( )
185+ // Create "grep" command with pattern, set stdin and stdout to piped
186+ // Spawn process
187+ // Write input lines to child stdin
188+ // Drop stdin to close pipe
189+ // Read output from child stdout line by line
190+ // Collect and return matching lines
191+ let mut child = Command :: new ( "grep" )
192+ . arg ( pattern)
193+ . stdin ( Stdio :: piped ( ) )
194+ . stdout ( Stdio :: piped ( ) )
195+ . spawn ( )
196+ . unwrap ( ) ;
197+
198+ let mut stdin = child. stdin . take ( ) . unwrap ( ) ;
199+ stdin. write_all ( input. as_bytes ( ) ) . unwrap ( ) ;
200+ drop ( stdin) ;
201+
202+ let mut output = String :: new ( ) ;
203+ child
204+ . stdout
205+ . take ( )
206+ . unwrap ( )
207+ . read_to_string ( & mut output)
208+ . unwrap ( ) ;
209+
210+ child. wait ( ) . unwrap ( ) ;
211+
212+ output
171213}
172214
173215#[ cfg( test) ]
0 commit comments