双引号令人困惑

双引号令人困惑

我了解到,当我使用命令时,双引号将除 $, `, \ 之外的所有内容视为字符。

但是,当使用类似命令时,find -type f -name "*.jpg" *.jpg它位于双引号内。那么,这意味着我们想将*.视为一个角色。因此,该find命令应该输出具有名称的常规文件*.jpg,而不是实现路径名扩展。

如果我们想做路径名扩展,我想我必须输入命令find -type f -name *.jpg(不带双引号)。

但是,结果是一样的。为什么在此命令中使用双引号?

答案1

通配符扩展的工作原理有一个微妙之处。更改为不包含 .jpg 文件的目录并输入

echo *.jpg

它会输出

*.jpg

特别是,字符串 *.jpg 保持不变。但是,如果您更改为包含 .jpg 文件的目录,例如假设我们有两个文件:image1.jpg 和 image2.jpg,则 echo *.jpg 命令将不会输出

image1.jpg image2.jpg

并且 *.jpg 被扩展。

如果您输入

find . -name *.jpg

并且当您键入此内容时所在目录中没有 .jpg 文件,则 find 将收到参数“.”、“-name”和“*.jpg”。但是,如果您在包含 .jpg 文件(例如 image1.jpg 和 image2.jpg)的目录中键入此命令,则 find 将收到参数“.”、“-name”、“image1.jpg”和“image2.jpg” “,所以实际上会运行命令

find . -name image1.jpg image2.jpg

并发现会抱怨。如果省略引号,真正令人困惑的是是否只有一个 .jpg 文件(例如 image1.jpg)。那么通配符扩展将导致

find . -name image1.jpg

find 命令将查找所有基名为 image1.jpg 的文件。

旁白:这确实导致了一个有用的 bash 习惯用法,用于查看是否有任何文件与给定模式匹配:

if [ "$(echo *.jpg)" = "*.jpg" ]; then
    # *.jpg has no matches
else
    # *.jpg has matches
fi

但请注意,如果当前目录中有名为“*.jpg”的文件,则此操作将不起作用。为了更加防水,你可以这样做

if [ "$(echo *.jpg)" = "*.jpg" ] && [ ! -e "*.jpg" ]; then
    # *.jpg has no matches
else
    # *.jpg has matches
fi

(虽然与问题没有直接相关,但我添加了这一点,因为它说明了通配符扩展如何工作的一些方面。)

答案2

您需要转义名称模式中的星号,因为find想要在它搜索的所有各个目录中进行自己的全局扩展。如果不进行转义,则*shell 会扩展 ,并且仅针对当前目录。这可能会产生非法find调用。

相关内容