![使用 GNU find 的 -printf 谓词时如何替换?](https://linux22.com/image/207724/%E4%BD%BF%E7%94%A8%20GNU%20find%20%E7%9A%84%20-printf%20%E8%B0%93%E8%AF%8D%E6%97%B6%E5%A6%82%E4%BD%95%E6%9B%BF%E6%8D%A2%EF%BC%9F.png)
我的查找命令:
find * -type d -printf '%p\n'
这是结果:
Icons
Index
Index/Team
Index/Pricing
Index/WhyUs
Navbar
Share
我想得到这个结果:
Icons components/Icons/Exports
Index components/Index/Exports
IndexTeam components/Index/Team/Exports
IndexPricing components/Index/Pricing/Exports
IndexWhyUs components/Index/WhyUs/Exports
Navbar components/Navbar/Exports
Share components/Share/Exports
我可以将 find 命令更改为:
find * -type d -printf '%p\tcomponents/%p/Exports\n'
但我得到这个结果:
Icons components/Icons/Exports
Index components/Index/Exports
Index/Team components/Index/Team/Exports
Index/Pricing components/Index/Pricing/Exports
Index/WhyUs components/Index/WhyUs/Exports
Navbar components/Navbar/Exports
Share components/Share/Exports
如何替换第一个中的斜杠%p
?
答案1
-printf
(特定于 GNU 实现的谓词find
)不提供对不同指令进行任何修改的规定,除了带有// ...的%x
字符串填充/截断指令之外。%5p
%-5p
%.5p
但在这里,你不需要find
。带壳zsh
:
for f (**/*(N/)) printf '%s\tcomponents/%s/Exports\n' ${f:gs|/||} $f
它还具有为您提供排序列表并排除隐藏目录的好处。
find
如果您使用 GNU 对输出进行后处理,则可以执行相同的操作,sort
例如gawk
:
find . ! -name . -type d -print0 |
sort -z |
LC_ALL=C gawk -v RS='\0' '
{
name = path = substr($0, 3)
gsub("/", "", name)
print name"\tcomponents/"path"/Exports"
}'
或者排除隐藏的,例如zsh
:
LC_ALL=C find . ! -name . '(' -name '.*' -prune -o -type d -print0 ')' |
sort -z |
LC_ALL=C gawk -v RS='\0' '
{
name = path = substr($0, 3)
gsub("/", "", name)
print name"\tcomponents/"path"/Exports"
}'
另请注意,在 中find *
,shell*
首先扩展到当前目录中的文件列表并将它们传递到find
.这意味着:
- 当前目录中的隐藏文件被排除(但不在子目录中,因为它是
find
找到这些文件的)。 - 如果任何文件名以
-
查找谓词开头,这会造成混淆find
- 顶级列表将被排序(因为 shell 默认对其全局扩展进行排序),但子级别不会被排序(因为 shell
find
不会排序) - 如果当前目录中有很多非隐藏文件,您可能会遇到arg 列表太长尝试
find
使用太大的列表执行时出错。
如果我们替换find *
为find .
,那么它就会find
在其中查找文件,并且上面的所有问题都可以避免。这也意味着.
(起点)将在列表中,因此我们需要使用! -name .
or -mindepth 1
(GNU 扩展名)将其排除,并且./
我们在此处删除的输出上将显示一个前缀,substr($0, 3)
尽管我们也可以使用 GNUfind
来-printf '%P\0'
代替-print0
反而。