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
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