From 95b7dc36e7219e94ada3dd4dd751cc3221e9b0e3 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sun, 16 Aug 2026 01:43:09 +0000 Subject: [PATCH] shell: accept seq --separator=X and --terminator=X The seq builtin only matched the long options spelled as a separate argument (--separator X), so the --separator=X spelling fell through to operand parsing and failed with "seq: invalid argument". Take the value after the = in the same arm that handles the attached -sX / -tX forms. --- src/runtime/shell/builtin/seq.rs | 14 +++++--- test/js/bun/shell/commands/seq.test.ts | 48 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/runtime/shell/builtin/seq.rs b/src/runtime/shell/builtin/seq.rs index fbad2252f12f..979977edffe9 100644 --- a/src/runtime/shell/builtin/seq.rs +++ b/src/runtime/shell/builtin/seq.rs @@ -60,8 +60,11 @@ impl Seq { idx += 1; continue; } - if arg.starts_with(b"-s") && arg.len() > 2 { - Self::state_mut(interp, cmd).separator = bun_ptr::RawSlice::new(&arg[2..]); + if let Some(bytes) = arg + .strip_prefix(b"-s") + .or_else(|| arg.strip_prefix(b"--separator=")) + { + Self::state_mut(interp, cmd).separator = bun_ptr::RawSlice::new(bytes); idx += 1; continue; } @@ -75,8 +78,11 @@ impl Seq { idx += 1; continue; } - if arg.starts_with(b"-t") && arg.len() > 2 { - Self::state_mut(interp, cmd).terminator = bun_ptr::RawSlice::new(&arg[2..]); + if let Some(bytes) = arg + .strip_prefix(b"-t") + .or_else(|| arg.strip_prefix(b"--terminator=")) + { + Self::state_mut(interp, cmd).terminator = bun_ptr::RawSlice::new(bytes); idx += 1; continue; } diff --git a/test/js/bun/shell/commands/seq.test.ts b/test/js/bun/shell/commands/seq.test.ts index 5ff6b24aefbc..ec8dbdb9dc9d 100644 --- a/test/js/bun/shell/commands/seq.test.ts +++ b/test/js/bun/shell/commands/seq.test.ts @@ -66,6 +66,30 @@ describe("seq", async () => { .stderr("") .runAsTest("--separator works"); + TestBuilder.command`seq --separator=, 0 5` + .exitCode(0) + .stdout("0,1,2,3,4,5,") + .stderr("") + .runAsTest("--separator=value works"); + + TestBuilder.command`seq --separator= 0 5` + .exitCode(0) + .stdout("012345") + .stderr("") + .runAsTest("--separator= sets an empty separator"); + + TestBuilder.command`seq --separator=a=b 0 2` + .exitCode(0) + .stdout("0a=b1a=b2a=b") + .stderr("") + .runAsTest("--separator=value splits at the first = only"); + + TestBuilder.command`seq --separator, 0 5` + .exitCode(1) + .stdout("") + .stderr("seq: invalid argument\n") + .runAsTest("--separator needs = before an attached value"); + TestBuilder.command`seq -t, 0 5`.exitCode(0).stdout("0\n1\n2\n3\n4\n5\n,").stderr("").runAsTest("-t works inline"); TestBuilder.command`seq -t , 0 5`.exitCode(0).stdout("0\n1\n2\n3\n4\n5\n,").stderr("").runAsTest("-t works separate"); @@ -76,12 +100,36 @@ describe("seq", async () => { .stderr("") .runAsTest("--terminator works"); + TestBuilder.command`seq --terminator=, 0 5` + .exitCode(0) + .stdout("0\n1\n2\n3\n4\n5\n,") + .stderr("") + .runAsTest("--terminator=value works"); + + TestBuilder.command`seq --terminator= 0 2` + .exitCode(0) + .stdout("0\n1\n2\n") + .stderr("") + .runAsTest("--terminator= sets an empty terminator"); + + TestBuilder.command`seq --terminator, 0 5` + .exitCode(1) + .stdout("") + .stderr("seq: invalid argument\n") + .runAsTest("--terminator needs = before an attached value"); + TestBuilder.command`seq -s. -t, 0 5` .exitCode(0) .stdout("0.1.2.3.4.5.,") .stderr("") .runAsTest("-s and -t work together"); + TestBuilder.command`seq --separator=. --terminator=, 0 5` + .exitCode(0) + .stdout("0.1.2.3.4.5.,") + .stderr("") + .runAsTest("--separator=value and --terminator=value work together"); + TestBuilder.command`seq 0`.exitCode(0).stdout("1\n0\n").stderr("").runAsTest("seq 0"); TestBuilder.command`seq 1`.exitCode(0).stdout("1\n").stderr("").runAsTest("seq 1");