diff --git a/src/commands/classified/external.rs b/src/commands/classified/external.rs index 463d50c3d4..aa009dbf20 100644 --- a/src/commands/classified/external.rs +++ b/src/commands/classified/external.rs @@ -7,6 +7,7 @@ use nu_errors::ShellError; use nu_parser::ExternalCommand; use nu_protocol::{UntaggedValue, Value}; use std::io::{Error, ErrorKind}; +use std::ops::Deref; use subprocess::Exec; use super::ClassifiedInputStream; @@ -107,11 +108,7 @@ pub(crate) async fn run_external_command( None } else { // Let's also replace ~ as we shell out - let arg = if let Some(ref home_dir) = home_dir { - arg.replace("~", home_dir.to_str().unwrap()) - } else { - arg.replace("~", "~") - }; + let arg = shellexpand::tilde_with_context(arg.deref(), || home_dir.as_ref()); Some(arg.replace("$it", &i)) } @@ -125,11 +122,7 @@ pub(crate) async fn run_external_command( process = Exec::cmd(&command.name); for arg in command.args.iter() { // Let's also replace ~ as we shell out - let arg = if let Some(ref home_dir) = home_dir { - arg.replace("~", home_dir.to_str().unwrap()) - } else { - arg.replace("~", "~") - }; + let arg = shellexpand::tilde_with_context(arg.deref(), || home_dir.as_ref()); let arg_chars: Vec<_> = arg.chars().collect(); if arg_chars.len() > 1 && arg_chars[0] == '"' && arg_chars[arg_chars.len() - 1] == '"' { @@ -137,7 +130,7 @@ pub(crate) async fn run_external_command( let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect(); process = process.arg(new_arg); } else { - process = process.arg(arg.clone()); + process = process.arg(arg.as_ref()); } } } diff --git a/tests/external_tests.rs b/tests/external_tests.rs index 0d810acac1..6b3c3fac56 100644 --- a/tests/external_tests.rs +++ b/tests/external_tests.rs @@ -1,5 +1,7 @@ mod helpers; +use helpers::Playground; + #[test] fn external_command() { let actual = nu!( @@ -9,3 +11,32 @@ fn external_command() { assert!(actual.contains("1")); } + +#[test] +fn spawn_external_process_with_home_in_arguments() { + Playground::setup("echo_tilde", |dirs, _| { + let actual = nu!( + cwd: dirs.test(), + r#" + sh -c "echo ~" + "# + ); + + assert!( + !actual.contains("~"), + format!("'{}' should not contain ~", actual) + ); + }) +} + +#[test] +fn spawn_external_process_with_tilde_in_arguments() { + let actual = nu!( + cwd: "tests/fixtures", + r#" + sh -c "echo 1~1" + "# + ); + + assert_eq!(actual, "1~1"); +}