一尘不染

查找和基名不能很好地播放

linux

我想在Linux命令行上回显查找的文件名部分。我尝试使用以下内容:

find www/*.html -type f -exec sh -c "echo $(basename {})" \;

find www/*.html -type f -exec sh -c "echo `basename {}`" \;

以及转义和引用文本各个部分的其他组合。结果是该路径未被剥离:

www/channel.html
www/definition.html
www/empty.html
www/index.html
www/privacypolicy.html

为什么不?

更新:尽管我在下面有一个可行的解决方案,但我仍然对为什么“基本名称”没有执行应做的事情感兴趣。


阅读 177

收藏
2020-06-03

共1个答案

一尘不染

您最初尝试的麻烦:

find www/*.html -type f -exec sh -c "echo $(basename {})" \;

$(basename {})代码在执行find命令之前执行一次。单曲的输出basename{}因为它是{}文件名的基本名称。因此,由find执行的命令是:

sh -c "echo {}"

为找到的每个文件,但find实际上每次都替换原始的(未修改的)文件名,因为{}字符出现在要执行的字符串中。

如果您希望它起作用,则可以使用单引号而不是双引号:

find www/*.html -type f -exec sh -c 'echo $(basename {})' \;

但是,echo将标准输出重复到标准basename输出无论如何都是没有意义的:

find www/*.html -type f -exec sh -c 'basename {}' \;

当然,我们可以进一步减少到:

find www/*.html -type f -exec basename {} \;

您还能在这里解释单引号和双引号之间的区别吗?

这是常规的shell行为。让我们采取一个略有不同的命令(但仅略微-
文件名可以在www目录下的任何位置,而不仅仅是向下一级),然后查看命令的单引号(SQ)和双引号(DQ)版本。命令:

find www -name '*.html' -type f -exec sh -c "echo $(basename {})" \;   # DQ
find www -name '*.html' -type f -exec sh -c 'echo $(basename {})' \;   # SQ

单引号将直接包含在命令中的材料传递给命令。因此,在SQ命令行中,启动的shell find删除了引号,该find命令将其$9参数视为:

echo $(basename {})

因为外壳会删除引号。相比之下,双引号中的材料由外壳处理。因此,在DQ命令行外壳(即发射find-而不是一个推出
find),看到$(basename {})串并执行它的一部分,取回{},所以它传递到字符串find作为它的$9参数是:

echo {}

现在,什么时候find执行-exec操作,在两种情况下都将其替换为{}刚找到的文件名(出于论证目的www/pics/index.html)。因此,您将执行两个不同的命令:

sh -c 'echo $(basename www/pics/index.html)'    # SQ
sh -c "echo www/pics/index.html"                # DQ

那里有一个(轻微的)符号作弊-这些是您在shell中键入的等效命令。的$2,实际上是启动了壳中有在任何情况下,没有引号-启动的外壳没有看到任何报价。

如您所见,DQ命令只是回显文件名。SQ命令运行该basename命令并捕获其输出,然后回显捕获的输出。一点简化主义者的思想表明,DQ命令可以写为-print而不是使用-exec,SQ命令可以写为-exec basename {} \;

如果您使用的是GNU
find,则它支持该-printf操作,随后可以执行格式指令,从而basename无需运行。但是,这仅在GNU中可用find;此处的其余讨论适用于find您可能遇到的任何版本。

2020-06-03