Skip to content

Conform redirections: ambiguous redirect + noclobber (batch80) - #278

Merged
brianjfox merged 2 commits into
mainfrom
fix/testsuite-batch80
Jul 24, 2026
Merged

Conform redirections: ambiguous redirect + noclobber (batch80)#278
brianjfox merged 2 commits into
mainfrom
fix/testsuite-batch80

Conversation

@brianjfox

Copy link
Copy Markdown
Owner

Summary

Two coherent redirection-conformance fixes surfaced by redir.tests (byte-diff 186 → 178, no regressions elsewhere).

1. Ambiguous redirect (closes #277)

A redirection target is expanded (brace, parameter/command/arithmetic substitution, word splitting, pathname expansion) and bash requires the result to be exactly one word; zero or multiple words is an ambiguous redirect. gnash used expand_no_split (joining fields into one literal word), so z="a b"; cat < $z opened a file literally named a b.

New expand_redir_target runs the full pipeline and errors with the original unexpanded word text when the result isn't a single word. Applied to every filename redirection (<, >, >|, >>, <>, &>, &>>, {var}<file) and to the fd-dup operators (<&word / >&word).

$ z="a b"; cat < $z          → gnash: line 1: $z: ambiguous redirect
$ cat < $undefined            → gnash: line 1: $undefined: ambiguous redirect
$ echo hi > {a,b}             → gnash: line 1: {a,b}: ambiguous redirect
$ exec 3<&$unset             → gnash: line 1: $unset: ambiguous redirect

2. noclobber

set -o noclobber / set -C / -C was recognized but had no effect. Wire opt_noclobber through set/set -o, $-, and $SHELLOPTS, and honor it when opening a truncating output redirection.

open_redir_output mirrors bash's noclobber_open: a clobbering redirect (>/&>, not the overriding >|) refuses to overwrite an existing regular file (cannot overwrite existing file), creates a missing file exclusively, and writes to a non-regular file (device, fifo, /dev/null) without truncating. >>, &>>, and <> are unaffected.

Testing

  • ctest 22/22
  • Scoreboard: redir 186 → 178, zero regressions across the full test suite
  • Verified each case byte-for-byte against source-built bash 5.3

A redirection target undergoes brace, parameter, command, and arithmetic
expansion followed by word splitting and pathname expansion.  bash requires
the result to be exactly one word; anything else (an unset or empty variable,
a value that splits on IFS, a glob matching several files, a brace expansion)
is an "ambiguous redirect" (redir.c redirection_expand).

gnash expanded redirect targets with expand_no_split, joining all fields into
a single literal word, so `cat < $z' with z="a b" tried to open a file named
`a b' instead of reporting the ambiguity.  Add expand_redir_target, which runs
the full expand_args pipeline and errors with the original unexpanded word text
when the result is not a single word.  Apply it to every filename redirection
(<, >, >|, >>, <>, &>, &>>, and the {var}<file form) and to the fd-dup
operators (<&word / >&word), which likewise reject a word that splits to zero
or several fields.

Closes #277.
`set -o noclobber' / `set -C' / `-C' was recognized as an option name but had
no effect: `>' truncated existing files unconditionally.  Wire opt_noclobber
through set/set -o, $-, and $SHELLOPTS, and honor it when opening a truncating
output redirection.

open_redir_output mirrors bash's noclobber_open (redir.c): under noclobber a
clobbering redirect (`>' or `&>', not the overriding `>|') refuses to overwrite
an existing regular file with `cannot overwrite existing file', creates a
missing file exclusively, and writes to a non-regular file (device, fifo,
/dev/null) without truncating.  Append (`>>', `&>>') and read-write (`<>')
redirections are unaffected.
@brianjfox
brianjfox merged commit 0bd4505 into main Jul 24, 2026
1 check passed
@brianjfox
brianjfox deleted the fix/testsuite-batch80 branch July 24, 2026 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Redirect targets that expand to zero or multiple words should be 'ambiguous redirect'

1 participant