Skip to main content

Fixed: "zsh: no matches found" for a URL with a ? or a --include=*.cs Option

· 4 min read
Jagdish Kumawat
Founder @ Dewiride

curl http://localhost:5190/demo/enum?status=placed and grep -rn 'class' src --include=*.cs both failed with zsh: no matches found, and neither program ever ran. Commands like these work in bash, and they appear that way in a lot of tutorials. In zsh, you have to quote them.

What I Was Doing​

I was searching a project for a word, and calling an API, in zsh, the default shell on macOS:

Terminal
grep -rn 'class' src --include=*.cs
curl -s http://localhost:5190/demo/enum?status=placed

What I Expected​

Search results, and a response.

What I Got​

Output
% grep -rn 'class' src --include=*.cs
zsh: no matches found: --include=*.cs
Output
% curl -s http://localhost:5190/demo/enum?status=placed
zsh: no matches found: http://localhost:5190/demo/enum?status=placed

Two commands in zsh, each failing with zsh: no matches found, one naming --include=*.cs and one naming a URL with a question mark.

What I Checked​

Who printed it. The message starts with zsh:. So neither grep nor curl was involved.

The same command in bash.

Terminal
bash -c "grep -rn 'class' src --include=*.cs"
Output
src/Sample.cs:1:class A {}

The docs. * and ? are file patterns, and the shells disagree on what to do when no file matches. The zsh manual says of its NOMATCH option, which is on by default: "If a pattern for filename generation has no matches, print an error, instead of leaving it unchanged in the argument list." The bash manual says: "If no matching filenames are found, and the shell option nullglob is disabled, the word is left unchanged."

Why It Happens​

zsh looks at each word before running the command. --include=*.cs has a *, and a URL with a query string has a ?. So they're patterns, and no file has those names. zsh reports it and stops, where bash would pass them on as they are.

The Fix​

Quote the word, which works in every shell:

Terminal
grep -rn 'class' src --include='*.cs'
curl -s 'http://localhost:5190/demo/enum?status=placed'

There are two zsh-only alternatives. noglob turns patterns off for one command, and setopt nonomatch makes zsh act like bash from then on:

Terminal
noglob grep -rn 'class' src --include=*.cs

After the Fix​

Output
% grep -rn 'class' src --include='*.cs'
src/Sample.cs:1:class A {}

The grep with --include='*.cs' in quotes finding src/Sample.cs:1 A .

noglob and setopt nonomatch gave the same result.

Common Mistakes​

MistakeWhat happensDo this instead
Putting setopt nonomatch in ~/.zshrc and forgettingA real typo in a file pattern goes to the programQuote what you mean
Quoting only part of a URLA later ? or * still countsQuote all of it
Using double quotes around $ in a URLThe shell fills in variablesUse single quotes

Troubleshooting​

SymptomLikely causeFix
A file with that name exists, and the option gets the wrong valueThe pattern matched itQuote it
zsh: ===== not foundA word starting with =The fix
The URL's & starts a background job& means that to the shellQuote it

Conclusion​

In zsh, an unquoted word with * or ? must match a file, or the command doesn't run. Quote URLs and patterns you mean for the program.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.