为什么文件数超过 1时可以find . -name "*.jav"
工作而不能工作?它们的作用是什么?为什么不将其解释为文字字符串?find . -name *.jav
.jav
" "
"*.jav"
答案1
通配符由 shell 扩展,而不是由命令扩展。find
是少数几个在其自身时间中执行类似于 shell 的通配符匹配的命令之一。
当您运行时ls *.jav
,首先 shell 扩展*.jav
到匹配文件的列表,例如file1.jav
file2.jav
file3.jav
,然后 shellls
使用生成的参数列表进行调用file1.jav
file2.jav
file3.jav
。这就是为什么您会看到与 相同的文件名列表echo *.jav
,即使echo
对文件一无所知并且不关心其参数是否是文件名。
当你跑步时find . -name "*.jav"
:
- shell 解析命令行以识别特殊字符并将其拆分为单词和标点符号。这里只有一个单词列表
find
,.
,-name
,*.jav
其中*
被引用。既然*
被引用,那么就 shell 而言,它是一个普通字符。 - shell
find
使用指定的参数列表运行命令:.
,-name
,*.jav
。 find
*.jav
在当前目录下的任何目录中查找名称与模式匹配的文件。
当您运行find . -name *.jav
并且没有匹配的文件时*.jav
:
- shell 解析命令行以识别特殊字符并将其拆分为单词和标点符号。这里只是一个单词列表
find
,.
,-name
,*.jav
其中*
没有被引用。 - 由于该单词
*.jav
包含未加引号的通配符,因此 shell 会执行文件名生成。由于没有匹配的文件名,因此模式仍未展开。 - shell
find
使用结果参数列表运行该命令,即.
,-name
,*.jav
。 find
*.jav
在当前目录下的任何目录中查找名称与模式匹配的文件。
当您运行find . -name *.jav
并且当前目录包含file1.jav
,file2.jav
和file3.jav
:
- shell 解析命令行以识别特殊字符并将其拆分为单词和标点符号。这里只是一个单词列表
find
,.
,-name
,*.jav
其中*
没有被引用。 - 由于该单词
*.jav
包含不带引号的通配符,因此 shell 执行文件名生成:*.jav
被匹配文件名列表替换。 - shell
find
使用结果参数列表运行命令,即.
,-name
,file1.jav
,file2.jav
,file3.jav
。 find
当到达 时抱怨语法错误file2.jav
。
当您运行find . -name *.jav
并且当前目录包含单个匹配文件时file.jav
:
- shell 解析命令行以识别特殊字符并将其拆分为单词和标点符号。这里只是一个单词列表
find
,.
,-name
,*.jav
其中*
没有被引用。 - 由于该单词
*.jav
包含不带引号的通配符,因此 shell 执行文件名生成:*.jav
被匹配文件名列表替换。 - shell
find
使用结果参数列表运行该命令,即.
,-name
,file.jav
。 find
看到一个完全有效的命令,但它可能不是您想要的:find
被告知查找file.jav
在任何目录中调用的文件,而不是查找任何匹配的文件*.jav
。
(Shell 求值和扩展还有很多其他功能。我只提到了此处相关的功能。)
(我描述的是最常见 shell 的默认行为:sh、bash、dash、ksh 等,某些 shell 可以配置为显示错误,而不是运行带有未扩展通配符的命令,或者将不匹配的通配符扩展为空这些都没有帮助。)