diff --git a/crates/nu-cli/src/commands/classified/external.rs b/crates/nu-cli/src/commands/classified/external.rs index 6797865101..a23be94940 100644 --- a/crates/nu-cli/src/commands/classified/external.rs +++ b/crates/nu-cli/src/commands/classified/external.rs @@ -116,7 +116,23 @@ fn run_with_stdin( let mut command_args = vec![]; for arg in command.args.iter() { let value = evaluate_baseline_expr(arg, &context.registry, scope)?; - command_args.push(value.as_string()?.trim_end_matches('\n').to_string()); + // Do the cleanup that we need to do on any argument going out: + let trimmed_value_string = value.as_string()?.trim_end_matches('\n').to_string(); + + let value_string; + #[cfg(not(windows))] + { + value_string = trimmed_value_string + .replace('$', "\\$") + .replace('"', "\\\"") + .to_string() + } + #[cfg(windows)] + { + value_string = trimmed_value_string + } + + command_args.push(value_string); } let process_args = command_args diff --git a/tests/shell/pipeline/commands/external.rs b/tests/shell/pipeline/commands/external.rs index 7244e13d8d..387f10b46b 100644 --- a/tests/shell/pipeline/commands/external.rs +++ b/tests/shell/pipeline/commands/external.rs @@ -48,6 +48,20 @@ fn automatically_change_directory_with_trailing_slash_and_same_name_as_command() }) } +// #[test] +// fn correctly_escape_external_arguments() { +// let actual = nu!(cwd: ".", r#"^echo '[{"foo": "bar"}]' | from-json | to-json"#); + +// assert_eq!(actual, "{\"foo\":\"bar\"}"); +// } + +#[test] +fn correctly_escape_external_arguments() { + let actual = nu!(cwd: ".", r#"^echo '$0'"#); + + assert_eq!(actual, "$0"); +} + mod it_evaluation { use super::nu; use nu_test_support::fs::Stub::{EmptyFile, FileWithContent, FileWithContentToBeTrimmed};