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}