为何Bash会在命令执行前展开glob?含find命令报错问询
find Great question—this behavior isn’t a random quirk, it’s a core part of how Unix-style shells (like Bash) are built. Let me break down the reasoning behind this design choice:
1. The Shell’s Role as a Command Preprocessor
First, remember that Bash acts as your command interpreter before any tool (like find) even starts running. One of its key jobs is to parse and expand parts of your command line upfront—things like environment variables ($HOME), tilde expansion (~), and yes, glob patterns like *.bak.
This design lets the shell handle common pattern matching universally, so every command doesn’t have to reinvent the wheel. For example, when you run ls *.txt, Bash expands *.txt to all matching files first, then passes that list to ls. ls doesn’t need to understand glob syntax at all—it just gets a ready-to-use list of filenames.
2. Historical Efficiency & Reusability
Back in early Unix days, most command-line tools didn’t have built-in glob support. Putting glob expansion in the shell meant every utility could benefit from this functionality without extra code. This was a huge efficiency win: instead of writing glob parsing logic into ls, cp, mv, and every other tool, the shell handled it once for everyone.
This pattern stuck around because it worked well—developers didn’t have to duplicate work, and users got a consistent experience across tools.
3. Consistency for User Expectations
For most commands, shell glob expansion is exactly what you want. If you run cp *.bak backups/, you expect Bash to find all .bak files and pass them to cp—you don’t want cp to try to interpret *.bak itself. This consistency means you don’t have to memorize which tools support globs natively and which don’t; the shell handles the heavy lifting by default.
So Why Does find Break?
The find command is a special case because it has its own pattern-matching engine for parameters like -name. It expects a single pattern (like *.bak) to match against filenames as it traverses directories. When Bash expands *.bak to a list of files before find runs, find sees something like:
find . -name tim.bak example.bak
Now find thinks example.bak is an extra, unrecognized expression (not part of the -name argument)—hence the "Paths must precede expression" error. To fix this, you quote the glob to tell Bash not to expand it:
find . -name '*.bak'
Now *.bak is passed directly to find, which uses its own logic to match files as it searches.
内容的提问来源于stack exchange,提问作者user9685224

