execute/
lib.rs

1/*!
2# Execute
3
4This library is used for extending `Command` in order to execute programs more easily.
5
6## Usage
7
8```rust
9use std::process::Command;
10
11use execute::Execute;
12
13// ...
14```
15
16### Verify the Program
17
18Since `Command` is used for spawning a process of a command and the executed progrom is external which may not exist or may not be the program that we expected, we usually need to verify the external program at runtime.
19
20The `execute_check_exit_status_code` method can be used to execute a command and check its exit status. For example,
21
22```rust
23use std::process::Command;
24
25use execute::Execute;
26
27const FFMPEG_PATH: &str = "/path/to/ffmpeg";
28
29let mut first_command = Command::new(FFMPEG_PATH);
30
31first_command.arg("-version");
32
33if first_command.execute_check_exit_status_code(0).is_err() {
34    eprintln!("The path `{}` is not a correct FFmpeg executable binary file.", FFMPEG_PATH);
35}
36```
37
38### Execute and Get the Exit Status
39
40```rust,ignore
41use std::process::Command;
42
43use execute::Execute;
44
45const FFMPEG_PATH: &str = "/path/to/ffmpeg";
46
47let mut command = Command::new(FFMPEG_PATH);
48
49command.arg("-i");
50command.arg("/path/to/media-file");
51command.arg("/path/to/output-file");
52
53if let Some(exit_code) = command.execute().unwrap() {
54    if exit_code == 0 {
55        println!("Ok.");
56    } else {
57        eprintln!("Failed.");
58    }
59} else {
60    eprintln!("Interrupted!");
61}
62```
63
64### Execute and Get the Output
65
66#### Output to the Screen
67
68```rust,ignore
69use std::process::Command;
70
71use execute::Execute;
72
73const FFMPEG_PATH: &str = "/path/to/ffmpeg";
74
75let mut command = Command::new(FFMPEG_PATH);
76
77command.arg("-i");
78command.arg("/path/to/media-file");
79command.arg("/path/to/output-file");
80
81let output = command.execute_output().unwrap();
82
83if let Some(exit_code) = output.status.code() {
84    if exit_code == 0 {
85        println!("Ok.");
86    } else {
87        eprintln!("Failed.");
88    }
89} else {
90    eprintln!("Interrupted!");
91}
92```
93
94#### Output to Memory (Captured)
95
96```rust,ignore
97use std::process::{Command, Stdio};
98
99use execute::Execute;
100
101const FFMPEG_PATH: &str = "/path/to/ffmpeg";
102
103let mut command = Command::new(FFMPEG_PATH);
104
105command.arg("-i");
106command.arg("/path/to/media-file");
107command.arg("/path/to/output-file");
108
109command.stdout(Stdio::piped());
110command.stderr(Stdio::piped());
111
112let output = command.execute_output().unwrap();
113
114if let Some(exit_code) = output.status.code() {
115    if exit_code == 0 {
116        println!("Ok.");
117    } else {
118        eprintln!("Failed.");
119    }
120} else {
121    eprintln!("Interrupted!");
122}
123
124println!("{}", String::from_utf8(output.stdout).unwrap());
125println!("{}", String::from_utf8(output.stderr).unwrap());
126```
127
128### Execute and Input Data
129
130#### Input In-memory Data
131
132```rust
133use std::process::{Command, Stdio};
134
135use execute::Execute;
136
137# if cfg!(target_os = "linux") {
138let mut bc_command = Command::new("bc");
139
140bc_command.stdout(Stdio::piped());
141
142let output = bc_command.execute_input_output("2^99\n").unwrap();
143
144println!("Answer: {}", String::from_utf8(output.stdout).unwrap().trim_end());
145# }
146```
147
148#### Input from a Reader
149
150```rust
151use std::process::{Command, Stdio};
152use std::fs::File;
153
154use execute::Execute;
155
156# if cfg!(target_os = "linux") {
157let mut cat_command = Command::new("cat");
158
159cat_command.stdout(Stdio::piped());
160
161let mut file = File::open("Cargo.toml").unwrap();
162
163let output = cat_command.execute_input_reader_output(&mut file).unwrap();
164
165println!("{}", String::from_utf8(output.stdout).unwrap());
166# }
167```
168
169By default, the buffer size is 256 bytes. If you want to change that, you can use the `_reader_output2` or `_reader2` methods and define a length explicitly.
170
171For example, to change the buffer size to 4096 bytes,
172
173```rust
174use std::process::{Command, Stdio};
175use std::fs::File;
176
177use execute::generic_array::typenum::U4096;
178use execute::Execute;
179
180# if cfg!(target_os = "linux") {
181let mut cat_command = Command::new("cat");
182
183cat_command.stdout(Stdio::piped());
184
185let mut file = File::open("Cargo.toml").unwrap();
186
187let output = cat_command.execute_input_reader_output2::<U4096>(&mut file).unwrap();
188
189println!("{}", String::from_utf8(output.stdout).unwrap());
190# }
191```
192
193### Execute Multiple Commands and Pipe Them Together
194
195```rust
196use std::process::{Command, Stdio};
197
198use execute::Execute;
199
200# if cfg!(target_os = "linux") {
201let mut command1 = Command::new("echo");
202command1.arg("HELLO WORLD");
203
204let mut command2 = Command::new("cut");
205command2.arg("-d").arg(" ").arg("-f").arg("1");
206
207let mut command3 = Command::new("tr");
208command3.arg("A-Z").arg("a-z");
209
210command3.stdout(Stdio::piped());
211
212let output = command1.execute_multiple_output(&mut [&mut command2, &mut command3]).unwrap();
213
214assert_eq!(b"hello\n", output.stdout.as_slice());
215# }
216```
217
218### Run a Command String in the Current Shell
219
220The `shell` function can be used to create a `Command` instance with a single command string instead of a program name and scattered arguments.
221
222```rust
223use std::process::{Command, Stdio};
224
225use execute::{Execute, shell};
226
227# if cfg!(target_os = "linux") {
228let mut command = shell("cat /proc/meminfo");
229
230command.stdout(Stdio::piped());
231
232let output = command.execute_output().unwrap();
233
234println!("{}", String::from_utf8(output.stdout).unwrap());
235# }
236```
237
238### Parse a Command String at Runtime
239
240The `command` function can be used to create a `Command` instance with a single command string instead of a program name and scattered arguments. The difference between the `shell` function and the `command` function is that the former is interpreted by the current shell while the latter is parsed by this crate.
241
242```rust
243use std::process::{Command, Stdio};
244
245use execute::{Execute, command};
246
247# if cfg!(target_os = "linux") {
248let mut command = command("cat '/proc/meminfo'");
249
250command.stdout(Stdio::piped());
251
252let output = command.execute_output().unwrap();
253
254println!("{}", String::from_utf8(output.stdout).unwrap());
255# }
256```
257
258### Parse a Command String at Compile Time
259
260The `command!` macro can be used to create a `Command` instance with a single command string literal instead of a program name and scattered arguments.
261
262```rust
263use std::process::{Command, Stdio};
264
265use execute::Execute;
266
267# if cfg!(target_os = "linux") {
268let mut command = execute::command!("cat '/proc/meminfo'");
269
270command.stdout(Stdio::piped());
271
272let output = command.execute_output().unwrap();
273
274println!("{}", String::from_utf8(output.stdout).unwrap());
275# }
276```
277
278### Create a `Command` Instance by Providing Arguments Separately
279
280The `command_args!` macro can be used to create a `Command` instance with a program name and arguments separately. The program name and arguments can be non-literal.
281
282```rust
283use std::process::{Command, Stdio};
284
285use execute::Execute;
286
287# if cfg!(target_os = "linux") {
288let mut command = execute::command_args!("cat", "/proc/meminfo");
289
290command.stdout(Stdio::piped());
291
292let output = command.execute_output().unwrap();
293
294println!("{}", String::from_utf8(output.stdout).unwrap());
295# }
296```
297*/
298
299pub extern crate generic_array;
300
301#[cfg(unix)]
302use std::{env, ffi::OsString};
303use std::{
304    ffi::OsStr,
305    io::{self, ErrorKind, Read, Write},
306    process::{Command, Output, Stdio},
307};
308
309pub use execute_command_macro::{command, command_args};
310use execute_command_tokens::command_tokens;
311use generic_array::{
312    typenum::{IsGreaterOrEqual, True, U1, U256},
313    ArrayLength, GenericArray,
314};
315
316pub trait Execute {
317    /// Execute this command and get the exit status code. stdout and stderr will be set to `Stdio::null()`. By default, stdin is inherited from the parent.
318    fn execute(&mut self) -> Result<Option<i32>, io::Error>;
319
320    /// Execute this command and get the exit status code. By default, stdin, stdout and stderr are inherited from the parent.
321    fn execute_output(&mut self) -> Result<Output, io::Error>;
322
323    /// Execute this command and check the exit status code. stdout and stderr will be set to `Stdio::null()`. By default, stdin is inherited from the parent. It's usually used for checking whether the program is correct.
324    #[inline]
325    fn execute_check_exit_status_code(
326        &mut self,
327        expected_exit_status_code: i32,
328    ) -> Result<(), io::Error> {
329        match self.execute()? {
330            Some(exit_status_code) if exit_status_code == expected_exit_status_code => Ok(()),
331            _ => Err(io::Error::other("unexpected exit status")),
332        }
333    }
334
335    /// Execute this command and input in-memory data to the process. stdin will be set to `Stdio::piped()`. stdout and stderr will be set to `Stdio::null()`.
336    fn execute_input<D: ?Sized + AsRef<[u8]>>(
337        &mut self,
338        data: &D,
339    ) -> Result<Option<i32>, io::Error>;
340
341    /// Execute this command and input in-memory data to the process. stdin will be set to `Stdio::piped()`. By default, stdout and stderr are inherited from the parent.
342    fn execute_input_output<D: ?Sized + AsRef<[u8]>>(
343        &mut self,
344        data: &D,
345    ) -> Result<Output, io::Error>;
346
347    /// Execute this command and input data from a reader to the process. stdin will be set to `Stdio::piped()`. stdout and stderr will be set to `Stdio::null()`.
348    #[inline]
349    fn execute_input_reader(&mut self, reader: &mut dyn Read) -> Result<Option<i32>, io::Error> {
350        self.execute_input_reader2::<U256>(reader)
351    }
352
353    /// Execute this command and input data from a reader to the process. stdin will be set to `Stdio::piped()`. stdout and stderr will be set to `Stdio::null()`.
354    fn execute_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
355        &mut self,
356        reader: &mut dyn Read,
357    ) -> Result<Option<i32>, io::Error>;
358
359    /// Execute this command and input data from a reader to the process. stdin will be set to `Stdio::piped()`. By default, stdout and stderr are inherited from the parent.
360    #[inline]
361    fn execute_input_reader_output(&mut self, reader: &mut dyn Read) -> Result<Output, io::Error> {
362        self.execute_input_reader_output2::<U256>(reader)
363    }
364
365    /// Execute this command and input data from a reader to the process. stdin will be set to `Stdio::piped()`. By default, stdout and stderr are inherited from the parent.
366    fn execute_input_reader_output2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
367        &mut self,
368        reader: &mut dyn Read,
369    ) -> Result<Output, io::Error>;
370
371    // TODO execute_multiple
372
373    /// Execute this command as well as other commands and pipe their stdin and stdout, and get the exit status code. The stdout and stderr of the last process will be set to `Stdio::null()`. By default, the stdin of the first process is inherited from the parent.
374    fn execute_multiple(&mut self, others: &mut [&mut Command]) -> Result<Option<i32>, io::Error>;
375
376    /// Execute this command as well as other commands and pipe their stdin and stdout. By default, the stdin of the first process, the stdout and stderr of the last process are inherited from the parent.
377    fn execute_multiple_output(&mut self, others: &mut [&mut Command])
378        -> Result<Output, io::Error>;
379
380    /// Execute this command as well as other commands and pipe their stdin and stdout, and input in-memory data to the process, and get the exit status code. The stdin of the first process will be set to `Stdio::piped()`. The stdout and stderr of the last process will be set to `Stdio::null()`.
381    fn execute_multiple_input<D: ?Sized + AsRef<[u8]>>(
382        &mut self,
383        data: &D,
384        others: &mut [&mut Command],
385    ) -> Result<Option<i32>, io::Error>;
386
387    /// Execute this command as well as other commands and pipe their stdin and stdout, and input in-memory data to the process. The stdin of the first process will be set to `Stdio::piped()`. By default, the stdout and stderr of the last process are inherited from the parent.
388    fn execute_multiple_input_output<D: ?Sized + AsRef<[u8]>>(
389        &mut self,
390        data: &D,
391        others: &mut [&mut Command],
392    ) -> Result<Output, io::Error>;
393
394    /// Execute this command as well as other commands and pipe their stdin and stdout, and input data from a reader to the process, and get the exit status code. The stdin of the first process will be set to `Stdio::piped()`. The stdout and stderr of the last process will be set to `Stdio::null()`.
395    #[inline]
396    fn execute_multiple_input_reader(
397        &mut self,
398        reader: &mut dyn Read,
399        others: &mut [&mut Command],
400    ) -> Result<Option<i32>, io::Error> {
401        self.execute_multiple_input_reader2::<U256>(reader, others)
402    }
403
404    /// Execute this command as well as other commands and pipe their stdin and stdout, and input data from a reader to the process, and get the exit status code. The stdin of the first process will be set to `Stdio::piped()`. The stdout and stderr of the last process will be set to `Stdio::null()`.
405    fn execute_multiple_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
406        &mut self,
407        reader: &mut dyn Read,
408        others: &mut [&mut Command],
409    ) -> Result<Option<i32>, io::Error>;
410
411    /// Execute this command as well as other commands and pipe their stdin and stdout, and input data from a reader to the process. The stdin of the first process will be set to `Stdio::piped()`. By default, the stdout and stderr of the last process are inherited from the parent.
412    #[inline]
413    fn execute_multiple_input_reader_output(
414        &mut self,
415        reader: &mut dyn Read,
416        others: &mut [&mut Command],
417    ) -> Result<Output, io::Error> {
418        self.execute_multiple_input_reader_output2::<U256>(reader, others)
419    }
420
421    /// Execute this command as well as other commands and pipe their stdin and stdout, and input data from a reader to the process. The stdin of the first process will be set to `Stdio::piped()`. By default, the stdout and stderr of the last process are inherited from the parent.
422    fn execute_multiple_input_reader_output2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
423        &mut self,
424        reader: &mut dyn Read,
425        others: &mut [&mut Command],
426    ) -> Result<Output, io::Error>;
427}
428
429impl Execute for Command {
430    #[inline]
431    fn execute(&mut self) -> Result<Option<i32>, io::Error> {
432        self.stdout(Stdio::null());
433        self.stderr(Stdio::null());
434
435        Ok(self.status()?.code())
436    }
437
438    #[inline]
439    fn execute_output(&mut self) -> Result<Output, io::Error> {
440        self.spawn()?.wait_with_output()
441    }
442
443    #[inline]
444    fn execute_input<D: ?Sized + AsRef<[u8]>>(
445        &mut self,
446        data: &D,
447    ) -> Result<Option<i32>, io::Error> {
448        self.stdin(Stdio::piped());
449        self.stdout(Stdio::null());
450        self.stderr(Stdio::null());
451
452        let mut child = self.spawn()?;
453
454        child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
455
456        Ok(child.wait()?.code())
457    }
458
459    #[inline]
460    fn execute_input_output<D: ?Sized + AsRef<[u8]>>(
461        &mut self,
462        data: &D,
463    ) -> Result<Output, io::Error> {
464        self.stdin(Stdio::piped());
465
466        let mut child = self.spawn()?;
467
468        child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
469
470        child.wait_with_output()
471    }
472
473    #[inline]
474    fn execute_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
475        &mut self,
476        reader: &mut dyn Read,
477    ) -> Result<Option<i32>, io::Error> {
478        self.stdin(Stdio::piped());
479        self.stdout(Stdio::null());
480        self.stderr(Stdio::null());
481
482        let mut child = self.spawn()?;
483
484        {
485            let stdin = child.stdin.as_mut().unwrap();
486
487            let mut buffer: GenericArray<u8, N> = GenericArray::default();
488
489            loop {
490                match reader.read(&mut buffer) {
491                    Ok(0) => break,
492                    Ok(c) => stdin.write_all(&buffer[0..c])?,
493                    Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
494                    Err(err) => return Err(err),
495                }
496            }
497        }
498
499        Ok(child.wait()?.code())
500    }
501
502    #[inline]
503    fn execute_input_reader_output2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
504        &mut self,
505        reader: &mut dyn Read,
506    ) -> Result<Output, io::Error> {
507        self.stdin(Stdio::piped());
508
509        let mut child = self.spawn()?;
510
511        {
512            let stdin = child.stdin.as_mut().unwrap();
513
514            let mut buffer: GenericArray<u8, N> = GenericArray::default();
515
516            loop {
517                match reader.read(&mut buffer) {
518                    Ok(0) => break,
519                    Ok(c) => stdin.write_all(&buffer[0..c])?,
520                    Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
521                    Err(err) => return Err(err),
522                }
523            }
524        }
525
526        child.wait_with_output()
527    }
528
529    fn execute_multiple(&mut self, others: &mut [&mut Command]) -> Result<Option<i32>, io::Error> {
530        if others.is_empty() {
531            return self.execute();
532        }
533
534        self.stdout(Stdio::piped());
535        self.stderr(Stdio::null());
536
537        let mut child = self.spawn()?;
538
539        let others_length_dec = others.len() - 1;
540
541        for other in others.iter_mut().take(others_length_dec) {
542            other.stdin(child.stdout.unwrap());
543            other.stdout(Stdio::piped());
544            other.stderr(Stdio::null());
545
546            child = other.spawn()?;
547        }
548
549        let last_other = &mut others[others_length_dec];
550
551        last_other.stdin(child.stdout.unwrap());
552        last_other.stdout(Stdio::null());
553        last_other.stderr(Stdio::null());
554
555        Ok(last_other.status()?.code())
556    }
557
558    fn execute_multiple_output(
559        &mut self,
560        others: &mut [&mut Command],
561    ) -> Result<Output, io::Error> {
562        if others.is_empty() {
563            return self.execute_output();
564        }
565
566        self.stdout(Stdio::piped());
567        self.stderr(Stdio::null());
568
569        let mut child = self.spawn()?;
570
571        let others_length_dec = others.len() - 1;
572
573        for other in others.iter_mut().take(others_length_dec) {
574            other.stdin(child.stdout.unwrap());
575            other.stdout(Stdio::piped());
576            other.stderr(Stdio::null());
577
578            child = other.spawn()?;
579        }
580
581        let last_other = &mut others[others_length_dec];
582
583        last_other.stdin(child.stdout.unwrap());
584
585        last_other.spawn()?.wait_with_output()
586    }
587
588    fn execute_multiple_input<D: ?Sized + AsRef<[u8]>>(
589        &mut self,
590        data: &D,
591        others: &mut [&mut Command],
592    ) -> Result<Option<i32>, io::Error> {
593        if others.is_empty() {
594            return self.execute_input(data);
595        }
596
597        self.stdin(Stdio::piped());
598        self.stdout(Stdio::piped());
599        self.stderr(Stdio::null());
600
601        let mut child = self.spawn()?;
602
603        child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
604
605        let others_length_dec = others.len() - 1;
606
607        for other in others.iter_mut().take(others_length_dec) {
608            other.stdin(child.stdout.unwrap());
609            other.stdout(Stdio::piped());
610            other.stderr(Stdio::null());
611
612            child = other.spawn()?;
613        }
614
615        let last_other = &mut others[others_length_dec];
616
617        last_other.stdin(child.stdout.unwrap());
618        last_other.stdout(Stdio::null());
619        last_other.stderr(Stdio::null());
620
621        Ok(last_other.status()?.code())
622    }
623
624    fn execute_multiple_input_output<D: ?Sized + AsRef<[u8]>>(
625        &mut self,
626        data: &D,
627        others: &mut [&mut Command],
628    ) -> Result<Output, io::Error> {
629        if others.is_empty() {
630            return self.execute_input_output(data);
631        }
632
633        self.stdin(Stdio::piped());
634        self.stdout(Stdio::piped());
635        self.stderr(Stdio::null());
636
637        let mut child = self.spawn()?;
638
639        child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
640
641        let others_length_dec = others.len() - 1;
642
643        for other in others.iter_mut().take(others_length_dec) {
644            other.stdin(child.stdout.unwrap());
645            other.stdout(Stdio::piped());
646            other.stderr(Stdio::null());
647
648            child = other.spawn()?;
649        }
650
651        let last_other = &mut others[others_length_dec];
652
653        last_other.stdin(child.stdout.unwrap());
654
655        last_other.spawn()?.wait_with_output()
656    }
657
658    fn execute_multiple_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
659        &mut self,
660        reader: &mut dyn Read,
661        others: &mut [&mut Command],
662    ) -> Result<Option<i32>, io::Error> {
663        if others.is_empty() {
664            return self.execute_input_reader2::<N>(reader);
665        }
666
667        self.stdin(Stdio::piped());
668        self.stdout(Stdio::piped());
669        self.stderr(Stdio::null());
670
671        let mut child = self.spawn()?;
672
673        {
674            let stdin = child.stdin.as_mut().unwrap();
675
676            let mut buffer: GenericArray<u8, N> = GenericArray::default();
677
678            loop {
679                match reader.read(&mut buffer) {
680                    Ok(0) => break,
681                    Ok(c) => stdin.write_all(&buffer[0..c])?,
682                    Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
683                    Err(err) => return Err(err),
684                }
685            }
686        }
687
688        let others_length_dec = others.len() - 1;
689
690        for other in others.iter_mut().take(others_length_dec) {
691            other.stdin(child.stdout.unwrap());
692            other.stdout(Stdio::piped());
693            other.stderr(Stdio::null());
694
695            child = other.spawn()?;
696        }
697
698        let last_other = &mut others[others_length_dec];
699
700        last_other.stdin(child.stdout.unwrap());
701        last_other.stdout(Stdio::null());
702        last_other.stderr(Stdio::null());
703
704        Ok(last_other.status()?.code())
705    }
706
707    fn execute_multiple_input_reader_output2<
708        N: ArrayLength + IsGreaterOrEqual<U1, Output = True>,
709    >(
710        &mut self,
711        reader: &mut dyn Read,
712        others: &mut [&mut Command],
713    ) -> Result<Output, io::Error> {
714        if others.is_empty() {
715            return self.execute_input_reader_output2::<N>(reader);
716        }
717
718        self.stdin(Stdio::piped());
719        self.stdout(Stdio::piped());
720        self.stderr(Stdio::null());
721
722        let mut child = self.spawn()?;
723
724        {
725            let stdin = child.stdin.as_mut().unwrap();
726
727            let mut buffer: GenericArray<u8, N> = GenericArray::default();
728
729            loop {
730                match reader.read(&mut buffer) {
731                    Ok(0) => break,
732                    Ok(c) => stdin.write_all(&buffer[0..c])?,
733                    Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
734                    Err(err) => return Err(err),
735                }
736            }
737        }
738
739        let others_length_dec = others.len() - 1;
740
741        for other in others.iter_mut().take(others_length_dec) {
742            other.stdin(child.stdout.unwrap());
743            other.stdout(Stdio::piped());
744            other.stderr(Stdio::null());
745
746            child = other.spawn()?;
747        }
748
749        let last_other = &mut others[others_length_dec];
750
751        last_other.stdin(child.stdout.unwrap());
752
753        last_other.spawn()?.wait_with_output()
754    }
755}
756
757/// Create a `Command` instance which can be executed by the current command language interpreter (shell).
758#[cfg(unix)]
759#[inline]
760pub fn shell<S: AsRef<OsStr>>(cmd: S) -> Command {
761    use std::sync::LazyLock;
762
763    static SHELL: LazyLock<OsString> = LazyLock::new(|| {
764        env::var_os("SHELL").unwrap_or_else(|| OsString::from(String::from("sh")))
765    });
766
767    let mut command = Command::new(&*SHELL);
768
769    command.arg("-c");
770    command.arg(cmd);
771
772    command
773}
774
775/// Create a `Command` instance which can be executed by the current command language interpreter (shell).
776#[cfg(windows)]
777#[inline]
778pub fn shell<S: AsRef<OsStr>>(cmd: S) -> Command {
779    let mut command = Command::new("cmd.exe");
780
781    command.arg("/c");
782    command.arg(cmd);
783
784    command
785}
786
787/// Create a `Command` instance by parsing a command string.
788#[inline]
789pub fn command<S: AsRef<str>>(cmd: S) -> Command {
790    let tokens = command_tokens(cmd);
791
792    if tokens.is_empty() {
793        Command::new("")
794    } else {
795        let mut command = Command::new(&tokens[0]);
796
797        command.args(&tokens[1..]);
798
799        command
800    }
801}