使用 GNU find 的 -printf 谓词时如何替换?

使用 GNU find 的 -printf 谓词时如何替换?

我的查找命令:

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 默认对其全局扩展进行排序),但子级别不会被排序(因为 shellfind不会排序)
  • 如果当前目录中有很多非隐藏文件,您可能会遇到arg 列表太长尝试find使用太大的列表执行时出错。

如果我们替换find *find .,那么它就会find在其中查找文件,并且上面的所有问题都可以避免。这也意味着.(起点)将在列表中,因此我们需要使用! -name .or -mindepth 1(GNU 扩展名)将其排除,并且./我们在此处删除的输出上将显示一个前缀,substr($0, 3)尽管我们也可以使用 GNUfind-printf '%P\0'代替-print0反而。

相关内容