Git Bash on Windows mangles backslashes passed to native tools — regexes silently stop matching
Git Bash's MSYS layer rewrites [\\/] to [/] on the way into a native tool like ripgrep, so Windows backslash paths silently stop matching — match the separator with .{1,4}, or run the tool from PowerShell, and always verify with a counter-example.
MSYS vrstva Git Bash přepíše [\\/] na [/] cestou do nativního nástroje jako ripgrep, takže Windows cesty s backslashem tiše přestanou matchovat – oddělovač zapiš jako .{1,4}, nebo nástroj spusť z PowerShellu, a vždy ověř protipříkladem.
Symptom
From Git Bash you run a native Windows tool (ripgrep, findstr, anything not MSYS-built) with a regex that handles both path separators:
rg 'megan[\\/]Documents' --files-with-matches
It returns a handful of hits — all of them forward-slash occurrences. The backslash-path occurrences (the majority on Windows) are silently missing, and the incomplete result looks perfectly plausible.
Cause
The MSYS layer between Bash and a native executable post-processes arguments (path conversion and backslash handling). Your [\\/] arrives at the tool as [/]. Single-quoting in Bash doesn't protect you — the mangling happens after the shell, on the way into the native process.
The nastiest property: no error, no warning — just fewer matches, which in a migration or audit reads as "these files don't exist".
Fix
Pick any of the three, in order of preference:
Don't write
\\at all — match the separator with a class that survives the trip:.{1,4}or.(covers\,\\and/):rg 'megan.{1,4}Documents' --files-with-matchesVerify with a counter-example — whenever a search over Windows paths returns suspiciously few results, re-run a shorter pattern against one file where the match provably exists (
rg -c 'megan' that-file). One command distinguishes "no matches" from "mangled pattern".Run the native tool from PowerShell instead — no MSYS layer,
[\\/]works as written.
Notes
- The same mechanism is behind MSYS's famous path conversion (arguments that look like
/foobecomingC:\msys64\foo) —MSYS_NO_PATHCONV=1helps for paths, but the backslash handling in regex arguments is the sneakier sibling. - Treat any "grep found surprisingly little" moment on Windows as a tooling suspect first, filesystem fact second.
- The same collapse happens on the way into a heredoc, including a quoted one (
<<'EOF'), which is exactly where you expect literal text to survive. A regex written as[^()\\]lands in the file as[^()\]and the script dies on a syntax error — the loud, harmless case. The dangerous case is a regex that still parses:\\sarriving as\sturns a whitespace class into a literals, so a trailing-whitespace cleaner starts eating the letter "s" off the end of every word. Write files containing regexes with a real file-writing tool, or build the pattern fromString.fromCharCode/new RegExpwith escaped input — and always test the cleaner against real samples rather than reading it.