From 587843f09cadcf9668c33a11e65d58d4a62ba2d0 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sun, 19 May 2024 21:12:09 -0700 Subject: [PATCH] Pass command as first argument to `shell` (#2061) --- README.md | 17 +++++++++++++++-- src/evaluator.rs | 2 +- src/function.rs | 6 +++++- tests/functions.rs | 12 +++++++++++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fd0e7db..d67efc5 100644 --- a/README.md +++ b/README.md @@ -1347,6 +1347,18 @@ file. interpret `command` is the same shell that is used to evaluate recipe lines, and can be changed with `set shell := […]`. + `command` is passed as the first argument, so if the command is `'echo $@'`, + the full command line, with the default shell command `shell -cu` and `args` + `'foo'` and `'bar'` will be: + + ``` + 'shell' '-cu' 'echo $@' 'echo $@' 'foo' 'bar' + ``` + + This is so that `$@` works as expected, and `$1` refers to the first + argument. `$@` does not include the first positional argument, which is + expected to be the name of the program being run. + ```just # arguments can be variables file := '/sys/class/power_supply/BAT0/status' @@ -1362,9 +1374,10 @@ full := shell('echo $1', 'foo') ``` ```just -# using python as the shell +# Using python as the shell. Since `python -c` sets `sys.argv[0]` to `'-c'`, +# the first "real" positional argument will be `sys.argv[2]`. set shell := ["python3", "-c"] -olleh := shell('import sys; print(sys.argv[1][::-1]))', 'hello') +olleh := shell('import sys; print(sys.argv[2][::-1]))', 'hello') ``` #### Environment Variables diff --git a/src/evaluator.rs b/src/evaluator.rs index 1b0f946..0ccafb9 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -226,7 +226,7 @@ impl<'src, 'run> Evaluator<'src, 'run> { }) } - pub(crate) fn run_command(&self, command: &str, args: &[String]) -> Result { + pub(crate) fn run_command(&self, command: &str, args: &[&str]) -> Result { let mut cmd = self.settings.shell_command(self.config); cmd.arg(command); cmd.args(args); diff --git a/src/function.rs b/src/function.rs index 0133d9e..0321508 100644 --- a/src/function.rs +++ b/src/function.rs @@ -460,8 +460,12 @@ fn sha256_file(evaluator: &Evaluator, path: &str) -> Result { } fn shell(evaluator: &Evaluator, command: &str, args: &[String]) -> Result { + let args = iter::once(command) + .chain(args.iter().map(String::as_str)) + .collect::>(); + evaluator - .run_command(command, args) + .run_command(command, &args) .map_err(|output_error| output_error.to_string()) } diff --git a/tests/functions.rs b/tests/functions.rs index c2d718c..4631f55 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -779,7 +779,17 @@ fn shell_no_argument() { #[test] fn shell_minimal() { - assert_eval_eq("shell('echo $0 $1', 'justice', 'legs')", "justice legs"); + assert_eval_eq("shell('echo $1 $2', 'justice', 'legs')", "justice legs"); +} + +#[test] +fn shell_args() { + assert_eval_eq("shell('echo $@', 'justice', 'legs')", "justice legs"); +} + +#[test] +fn shell_first_arg() { + assert_eval_eq("shell('echo $0')", "echo $0"); } #[test]