我想在 linux 命令行上回显 find 的文件名部分。我尝试使用以下内容:
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 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 {} \;
Could you also explain the difference between single quotes and double quotes here?
这是常规的 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
单引号将包含的 Material 直接传递给命令。因此,在 SQ 命令行中,启动 find
的 shell 会删除封闭的引号,而 find
命令将其 $9
参数视为:
echo $(basename {})
因为外壳会删除引号。相比之下,双引号中的 Material 是由shell处理的。因此,在 DQ 命令行中,shell(启动 find
而非启动 by find
的 shell)看到 $( 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 中键入的等效命令。在这两种情况下,启动的 shell 的 $2
实际上都没有引号——启动的 shell 看不到任何引号。
如您所见,DQ 命令只是简单地回显文件名; SQ 命令运行 basename
命令并捕获其输出,然后回显捕获的输出。稍微简化一下思路,DQ命令可以写成-print
而不是-exec
,SQ命令可以写成-exec基本名称 {}\;
.
如果你使用的是 GNU find
,它支持 -printf
Action ,后面可以跟 Format Directives这样就不需要运行 basename
了。但是,这仅在 GNU find
中可用;此处的其余讨论适用于您可能遇到的任何版本的 find
。
https://stackoverflow.com/questions/15627446/