[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