Skip to content

Pass Cmd() and Bash() commands through without mangling their quotes - #9

Merged
tomlm merged 1 commit into
mainfrom
fix-cmd-quoting
Oct 19, 2026
Merged

tomlm merged 1 commit into
mainfrom
fix-cmd-quoting

Conversation

@tomlm

@tomlm tomlm commented Oct 19, 2026

Copy link
Copy Markdown
Owner

Any Cmd() or Bash() command with a quoted argument broke. In Boxcars, Cmd("az webapp config appsettings list ... --query \"[?name=='X'].value | [0]\" -o tsv") failed with exit code 2.

Cmd() on Windows

  • Cause: the command went to cmd.exe as a single argument, Command.Run("cmd.exe", ["/Q", "/C", cmd]). MedallionShell escapes each argument for argv parsing, so every " became \". But cmd.exe doesn't parse argv; it runs everything after /C as typed. Programs therefore received literal \", and a |, & or > inside the quotes ended up outside them as far as cmd.exe was concerned.

    Command passed to Cmd() Printed
    echo "[a | b]" \"[a | b]\"
    echo [a ^| b] [a | b]
  • Fix: Cmd() sets the raw command line itself, [/Q] /S /C "<cmd>", through opt.StartInfo(...). /S makes cmd.exe strip exactly the outer pair of quotes and leave the command's own quotes alone.

Bash()

  • Cause: it replaced " with \" before Command.Run, which escapes the argument again. Bash then saw \" (a literal quote) instead of quotes around an argument, so "a b" arrived as the two arguments "a and b".
  • Fix: pass the command as typed.

Tests

  • New: Test_Cmd_QuotedArguments, a quoted argument with spaces and a |.
  • New: Test_Bash_QuotedArguments, where "a b" must arrive as one argument.
  • Both fail on main and pass with this change.
  • The full suite passes: 317 tests.

Version

Bumped to 3.2.1, with a changelog entry in the README. The package is ready to publish from the portal.

🤖 Generated with Claude Code

Cmd() on Windows handed the command to cmd.exe as one argument, so it was
escaped for argv parsing: every " became \". cmd.exe doesn't parse argv; it
runs everything after /C as typed, so programs got literal \" and quoted
arguments broke, along with any | & > inside them. Cmd() now gives cmd.exe the
command line as-is: /S /C "<command>".

Bash() escaped the command's quotes before Command.Run escaped the argument
again, so bash saw \" (a literal quote) instead of quotes around an argument.
It now passes the command as typed.

Adds tests for quoted arguments with spaces and pipes, and bumps the version
to 3.2.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tomlm
tomlm merged commit a2f2f23 into main Oct 19, 2026
1 of 2 checks passed
@tomlm
tomlm deleted the fix-cmd-quoting branch October 19, 2026 20:06
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