我想在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
为什么不?
更新:尽管我在下面有一个可行的解决方案,但我仍然对为什么“基本名称”没有执行应做的事情感兴趣。
您最初尝试的麻烦:
是$(basename {})代码在执行find命令之前执行一次。单曲的输出basename是{}因为它是{}文件名的基本名称。因此,由find执行的命令是:
$(basename {})
find
basename
{}
sh -c "echo {}"
为找到的每个文件,但find实际上每次都替换原始的(未修改的)文件名,因为{}字符出现在要执行的字符串中。
如果您希望它起作用,则可以使用单引号而不是双引号:
find www/*.html -type f -exec sh -c 'echo $(basename {})' \;
但是,echo将标准输出重复到标准basename输出无论如何都是没有意义的:
echo
find www/*.html -type f -exec sh -c 'basename {}' \;
当然,我们可以进一步减少到:
find www/*.html -type f -exec basename {} \;
您还能在这里解释单引号和双引号之间的区别吗?
这是常规的shell行为。让我们采取一个略有不同的命令(但仅略微- 文件名可以在www目录下的任何位置,而不仅仅是向下一级),然后查看命令的单引号(SQ)和双引号(DQ)版本。命令:
www
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参数视为:
$9
echo $(basename {})
因为外壳会删除引号。相比之下,双引号中的材料由外壳处理。因此,在DQ命令行外壳(即发射find-而不是一个推出 的 find),看到$(basename {})串并执行它的一部分,取回{},所以它传递到字符串find作为它的$9参数是:
echo {}
现在,什么时候find执行-exec操作,在两种情况下都将其替换为{}刚找到的文件名(出于论证目的www/pics/index.html)。因此,您将执行两个不同的命令:
-exec
www/pics/index.html
sh -c 'echo $(basename www/pics/index.html)' # SQ sh -c "echo www/pics/index.html" # DQ
那里有一个(轻微的)符号作弊-这些是您在shell中键入的等效命令。的$2,实际上是启动了壳中有在任何情况下,没有引号-启动的外壳没有看到任何报价。
$2
如您所见,DQ命令只是回显文件名。SQ命令运行该basename命令并捕获其输出,然后回显捕获的输出。一点简化主义者的思想表明,DQ命令可以写为-print而不是使用-exec,SQ命令可以写为-exec basename {} \;。
-print
-exec basename {} \;
如果您使用的是GNU find,则它支持该-printf操作,随后可以执行格式指令,从而basename无需运行。但是,这仅在GNU中可用find;此处的其余讨论适用于find您可能遇到的任何版本。
-printf