[RFC] Preserve native Windows quoting with CYGWIN=noglob
Erik Demaine
edemaine@mit.edu
Tue Aug 25 18:26:47 GMT 2026
Dear Cygwin developers,
I am a long-time Cygwin user (30 years or so), but am new to its development
side, so let me know if I'm missing any protocol or best practices.
Cygwin's command-line argument processing when called from a non-Cygwin
process is a complex subject with lots of history (see below for links). I'd
like to propose (and happy to implement) a relatively small change:
PROPOSAL: CYGWIN=noglob mode handles quotes the same as CYGWIN=glob mode
There's currently a major asymmetry between the two, and noglob's behavior
with double quotes is arguably buggy, so I'm hoping we can break
backward-compatibility in this case. Here's some example code where
non-Cygwin NodeJS tries to pass literal arguments to Cygwin echo:
const { spawnSync } = require("node:child_process");
const echo = (arg, CYGWIN) =>
spawnSync("C:/cygwin64/bin/echo.exe", [arg],
{ env: { ...process.env, CYGWIN }, encoding: "utf8" },
).stdout.trimEnd();
console.log(` glob brace: ${echo("HEAD^{commit}", "glob")}`);
console.log(`noglob brace: ${echo("HEAD^{commit}", "noglob")}`);
console.log(` glob quote: ${echo('a"b', "glob")}`);
console.log(`noglob quote: ${echo('a"b', "noglob")}`);
The output on Cygwin 3.6.10-1 is:
glob brace: HEAD^commit
noglob brace: HEAD^{commit}
glob quote: a"b
noglob quote: a\b
noglob stops processing of braces, which is great, but messes up processing of
double quotes. This prevents calling a Cygwin program from a non-Cygwin
program while passing in the user's arguments literally with no processing
using standard Windows argument passing (as done by non-Cygwin Node's
child_process, non-Cygwin Python's subprocess, etc.),
Cygwin's documentation
<https://cygwin.com/doc/preview/cygwin-ug-net/using-cygwinenv.html> suggests
that [no]glob should only affect "command line arguments containing UNIX-style
file wildcard characters (brackets, braces, question mark, asterisk, escaped
with \)". So I'd argue that the different quote handling is a bug. And
changing the behavior hopefully has limited unintended impact, given that it's
hidden behind the (obscure?) CYGWIN=noglob flag.
This behavior has been reported and analyzed several times:
* A 2011 report demonstrated the same a\"b -> a\b behavior with
CYGWIN=noglob, specifically mentioning lost quotes in Git commit
messages:
<https://cygwin.com/pipermail/cygwin/2011-November/198304.html>
* A 2016 discussion considered a native CreateProcess caller attempting
to pass an argv array verbatim with globbing disabled:
<https://cygwin.com/pipermail/cygwin/2016-May/227701.html>
<https://cygwin.com/pipermail/cygwin/2016-May/227720.html>
* A 2020 analysis identified the coupling between quoted() and globify()
and the incompatibility with the command line produced by Cygwin's own
argv serializer:
<https://cygwin.com/pipermail/cygwin/2020-June/245162.html>
* A comprehensive parser rewrite reached v6 in 2021:
<https://cygwin.com/pipermail/cygwin-patches/2021q2/011367.html>
Reviewers asked for its separate concerns to be split into focused
patches:
<https://cygwin.com/pipermail/cygwin-patches/2021q2/011369.html>
<https://cygwin.com/pipermail/cygwin-patches/2021q2/011372.html>
* A 2025 discussion reported an adjacent escaped-quote failure when a
native Windows tool launches a Cygwin program:
<https://cygwin.com/pipermail/cygwin/2025-August/258582.html>
The current call in dll_crt0_1 still combines two distinct decisions:
build_argv (line, __argv, __argc,
NOTSTATE (myself, PID_CYGPARENT) && allow_glob);
That boolean controls both how a native Windows command line is decoded
and whether glob expansion is performed. Consequently, noglob selects
the non-winshell quote-stripping path as well as disabling expansion.
My proposal is to narrow the scope from the 2021 rewrite:
1. Decode a native Windows command line using the same quote/backslash
rules regardless of CYGWIN=[no]glob.
2. Let allow_glob control only wildcard, bracket, brace, and tilde
expansion.
3. Preserve the existing glob-enabled and Cygwin-parent behavior.
If full backward compatibility is a requirement, then we could add another
flag parallel to [no]glob, something like [no]quote. I haven't thought about
the best design for this, given that the current implementation conflates the
two issues, but I imagine we could fogure it out through discussion.
Would a focused patch along these lines be welcome?
Thanks!
Erik
--
Erik Demaine | edemaine@mit.edu | https://erikdemaine.org/
More information about the Cygwin-developers
mailing list