Skip to content

truncate, paste, uniq: let a repeated option override the earlier one - #14258

Open
arbelonson-source wants to merge 1 commit into
uutils:mainfrom
arbelonson-source:fix/repeated-value-options-last-wins
Open

truncate, paste, uniq: let a repeated option override the earlier one#14258
arbelonson-source wants to merge 1 commit into
uutils:mainfrom
arbelonson-source:fix/repeated-value-options-last-wins

Conversation

@arbelonson-source

Copy link
Copy Markdown

GNU reads options left to right, so giving the same one twice keeps the last value. These three rejected the repeat outright.

Command GNU uutils before
truncate -s 1 -s 2 f truncates to 2 error: the argument '--size <SIZE>' cannot be used multiple times
paste -d, -d: f1 f2 joins with : error: the argument '--delimiters <LIST>' cannot be used multiple times
uniq -f 1 -f 2 f skips 2 fields error: the argument '--skip-fields <N>' cannot be used multiple times

Fixed with args_override_self(true), the same way cut already does it. For uniq this covers -s and -w as well, both checked against GNU.

Found by differential testing against GNU coreutils 9.11.

This is deliberately not applied everywhere. cut -f1 -f2 and join -1 1 -1 2 are errors in GNU too — just different ones ("only one list may be specified", "incompatible join fields 0, 1") — so those are left alone rather than swept up. cut in particular already documents in a comment why it uses ArgAction::Append to count occurrences.

Testing

One regression test per utility. Verified they catch the bug by reverting the three source files alone — all three fail, then pass with them restored.

  • cargo test --features "truncate,paste,uniq" --no-default-features: 99 passed, 0 failed (96 pre-existing, 3 new)
  • cargo fmt --check and cargo clippy -p uu_truncate -p uu_paste -p uu_uniq --all-targets: clean
  • 9-case differential check covering the repeated forms plus the single-option ones (truncate -s 3, paste -d,, uniq -f 1, bare uniq) as regression cover: all 9 match GNU

Disclosure

Prepared with AI assistance (Claude Code), per the AI policy in CONTRIBUTING.md. On the GPL point raised there: expected behavior was established by running the installed GNU binaries as a black box and recording their output. I did not read GNU coreutils source. All testing above was run locally.

GNU reads options left to right, so giving one twice keeps the last:

    $ truncate -s 1 -s 2 f     # GNU truncates to 2
    error: the argument '--size <SIZE>' cannot be used multiple times
    $ paste -d, -d: f1 f2      # GNU joins with ':'
    error: the argument '--delimiters <LIST>' cannot be used multiple times
    $ uniq -f 1 -f 2 f         # GNU skips 2 fields
    error: the argument '--skip-fields <N>' cannot be used multiple times

Set args_override_self, the same way cut already does.

This is not universal: `cut -f1 -f2` and `join -1 1 -1 2` are errors in
GNU too, just different ones, so those are left alone.
@github-actions

Copy link
Copy Markdown

Binary size comparison:

Individual binary size comparison VS main (threshold: >=5% AND >=4 KB).

Total size of compared binaries: 152.18 MB (+1004 KB, +0.65%)

Significant per-binary changes:
  comm     1.12 MB ->    2.33 MB  (+1.21 MB, +107.29%)

@github-actions

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/tail/tail-n0f (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/cut/bounded-memory (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/date/date-locale-hour (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/tail/symlink (passes in this run but fails in the 'main' branch)

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.

1 participant