我是 Bash 新手。从查找文件文档:
您想递归查找 ~/mydir 及其所有子目录中文件扩展名为 .htm(或 .HTM 或 .Htm...)的每个文件并将其删除。我见过很多尝试,例如 rm -rf ~/mydir/*.htm,但效果并不理想。正确的解决方案是
find ~/mydir -iname '*.htm' -exec rm {} \;
-iname
表示您要对文件名进行不区分大小写的搜索。'*.htm'
用单引号引起来是为了防止 bash 扩展 *,否则会产生意外结果。
问题:带引号和不带引号的星号会产生什么结果?为什么你决定使用引号而不是不使用引号?
答案1
如果不使用引号,shell 将扩展*.htm
为文件列表并将此列表传递给find
。如果使用引号,shell 将把五个字符的字符串*.htm
作为参数提供给find
。
例如,引用:
$ ls
a.htm b.htm
$ echo find . -iname '*.htm'
find . -iname *.htm
$ find . -iname '*.htm'
./b.htm
./a.htm
以上代码按预期运行。没有引号,find
给出了它不知道如何处理的参数:
$ echo find . -iname *.htm
find . -iname a.htm b.htm
$ find . -iname *.htm
find: paths must precede expression: b.htm
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
答案2
首先看一个例子,这里我们递归地查找所有带有.htm
扩展名(不区分大小写)的文件:
$ tree
.
├── spam
│ ├── egg.htm
│ └── egg.Htm
├── spam.htm
└── spam.Htm
$ find . -type f -iname *.htm
./spam.htm
./spam.Htm
$ find . -type f -iname '*.htm'
./spam.htm
./spam/egg.htm
./spam/egg.Htm
./spam.Htm
正如您所见,在第一种情况下,我没有使用任何引号-iname *.htm
,文件名首先经过了 glob( *
) 扩展(由 shell 在find
启动之前完成),因为我没有使用任何引号,因此导致:
find . -type f -iname spam.htm spam.Htm
即当前目录中所有带有扩展名的文件.htm
(不区分大小写)。因此,尽管./spam
子目录中有两个带有.htm
扩展名的文件,但它们不会被找到,因为我们现在正在寻找文件spam.htm
或spam.Htm
。
另一方面,在第二种情况下find . -type f -iname '*.htm'
,我们使用了引用,因此文件名不会受到全局扩展的影响,因此我们将得到所需的结果。
答案3
我相信你想了解的是一个称为“引用”的过程。引用适用于双引号和单引号。
如果将文本放在双引号内,则 shell 使用的所有特殊字符都将失去其含义,除了 $(美元符号)、\(反斜杠)和 `(反引号)。
单引号抑制所有扩展。
在这种情况下,转义字符也需要引起注意。您可以在字符前加上 \(反斜杠)以将其转换为转义字符。这通常在双引号内完成,以有选择地防止扩展。
echo "This bowl costs \$10.00"
This bowl costs $10.00
此处 $ 被称为转义字符。