Skip to content

Pass Unix commands to sh verbatim instead of escaping only quotes [patch] - #99

Merged
matt-edmondson merged 3 commits into
mainfrom
fix/unix-shell-argument-quoting
Oct 7, 2026
Merged

matt-edmondson merged 3 commits into
mainfrom
fix/unix-shell-argument-quoting

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #54

Problem

NativeCommandExecutor.CreateStartInfo built the Unix arguments as -c "<command>" and escaped only ". .NET splits Arguments using the MSVCRT rules, so backslashes already in the command combined with the inserted escapes, and sh got a mangled command. For example, echo "say \"hi\"" and echo trailing\ failed with Unterminated quoted string.

Change

  • netcoreapp2.1+ targets (net6–net10): -c and the command are passed through ProcessStartInfo.ArgumentList, so nothing is quoted at all.
  • netstandard2.1, which has no ArgumentList: the command is wrapped by a new internal QuoteArgument, an MSVCRT-correct escaper. A run of backslashes before a quote is doubled and the quote escaped, and a trailing run is doubled.
  • Windows (cmd.exe /c) is unchanged.

Tests

  • NativeCommandExecutor_Passes_Backslashes_And_Quotes_To_The_Shell_Verbatim runs both repro commands from the issue, plus one with a run of backslashes before a quote, through Execute and ExecuteAsync. It is limited to Linux/macOS.
  • NativeCommandExecutor_QuoteArgument_Round_Trips_Through_Arguments covers the netstandard path, which the net10.0 test project can't run directly. It passes QuoteArgument output through ProcessStartInfo.Arguments to printf %s and checks that the child gets each argument back unchanged.
  • Proven both ways. With the old Arguments line restored, all 3 verbatim cases fail. With a quotes-only escaper in place of QuoteArgument, 5 of the 9 round-trip cases fail.
  • Full suite on Linux: 963 passed, 0 failed. Release build of Essentials.CommandExecutors.Native is clean on all six targets, netstandard2.1 included.

🤖 Generated with Claude Code

https://claude.ai/code/session_01D7wytU6jsZ1cH3f6grCTz5


Generated by Claude Code

…tch]

NativeCommandExecutor built `-c "<command>"` by escaping only `"`, so
backslashes already in the command combined with the inserted escapes
under the MSVCRT splitting rules, and `echo "say \"hi\""` or
`echo trailing\` failed with "Unterminated quoted string".

On netcoreapp2.1+ the command now goes through ArgumentList, which needs
no quoting. netstandard2.1 has no ArgumentList, so it quotes the command
with a MSVCRT-correct escaper, tested by round-tripping arguments through
ProcessStartInfo.Arguments.

Fixes #54

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D7wytU6jsZ1cH3f6grCTz5
Comment thread Essentials.CommandExecutors.Native/NativeCommandExecutor.cs
Keeps this change from touching the lines #53's fix edits, so the two PRs merge in either order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D7wytU6jsZ1cH3f6grCTz5
A lone backslash at the end of an `sh -c` script is up to the shell: dash
keeps it, but the bash behind macOS's /bin/sh drops it as a line
continuation, so the macOS leg failed although the command reached the
shell verbatim. The case now ends in an even run of backslashes, which
every shell reads the same way and which still fails against the old
quotes-only escaping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D7wytU6jsZ1cH3f6grCTz5
@sonarqubecloud

sonarqubecloud Bot commented Oct 7, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 486803c into main Oct 7, 2026
14 checks passed
@matt-edmondson
matt-edmondson deleted the fix/unix-shell-argument-quoting branch October 7, 2026 12:22
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.

NativeCommandExecutor on Unix fails valid shell commands containing \" or ending in \ with "Unterminated quoted string"

2 participants