Skip to content

Pass script arguments like Bash: $0, $@, "$@", ${1:-x}, and the set -x trace - #294

Merged
certik merged 5 commits into
prefix-dev:mainfrom
certik:fix/script-args
Oct 21, 2026
Merged

certik merged 5 commits into
prefix-dev:mainfrom
certik:fix/script-args

Conversation

@certik

@certik certik commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Make scripts receive and forward their arguments like Bash. These are the fixes needed to run LFortran's build scripts, which take a build directory and forward CMake arguments, with shell on every platform.

Fixes #290, fixes #291, fixes #292, fixes #293.

The first commit fixes the lints that the current stable Rust (1.99) reports in existing code, which made the clippy job fail: miette's bail! used in expression position (semicolon_in_expressions_from_non_local_macros) and a drain().collect() into the same collection type. It doesn't change behavior.

Each fix is a separate commit with its own tests. crates/shell/tests/script_args.rs runs the shell binary on scripts, which covers main.rs, where the script arguments are set up.

Validation

  • cargo fmt -- --check
  • cargo clippy --all-targets --workspace -- -D warnings and cargo test --workspace --all-targets, on every commit, with Rust 1.99.1 (as in CI) and 1.95; the new tests fail without their fix
  • compared with Bash, "$@" gives the same words for no arguments, an empty argument, arguments with spaces, "pre$@post", x"$@"y and "$@$@"

Unquoted expansions are still not split on whitespace (for w in $v, unquoted $*), as before. That behaviour is unchanged here.

Rust 1.99 rejects a trailing semicolon in a macro used in expression
position (semicolon_in_expressions_from_non_local_macros), which miette's
bail! has. Use bail! as a statement instead. Also replace a
drain().collect() into the same collection type with std::mem::take.
The trace was written to stdout, so it ended up in the output of command
substitutions and pipes. Write it to stderr, as Bash does.

Fixes prefix-dev#293
$@ and $# were computed from the shell's own command line, including the
shell binary, its options and the script path, and $0 and $* were not
set. Set $0 to the script path (or the name the shell was invoked as)
and $@, $* and $# from the script arguments, as Bash does.

Fixes prefix-dev#290
Only names were accepted inside ${...}, so ${1}, ${1:-default}, ${10},
${@} and ${*} were output literally. Accept positional parameters
there, with modifiers for ${N}. Modifiers on ${@} and ${*}, such as the
${@:2} slice, are still not supported.

Fixes prefix-dev#292
"$@" expanded to a single word with all positional parameters joined by
spaces, so arguments could not be forwarded intact. Expand it to one word
per parameter, as Bash does: text around it joins the first and last
parameters, and with no parameters "$@" gives no word at all. Unquoted
$@ also gives one word per (non-empty) parameter. shift now updates $@
and $* as well.

Fixes prefix-dev#291
@certik
certik merged commit a80c930 into prefix-dev:main Oct 21, 2026
8 checks passed
@certik
certik deleted the fix/script-args branch October 21, 2026 06:55
@certik certik mentioned this pull request Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant