在查找上运行查找

在查找上运行查找

我对“linux run find on find”进行了网络搜索,但没有产生相关结果。我想通过查找构建文件列表,然后在该列表上再次运行查找。

在修复了一些“愚蠢”的错误后,我想由于命令行工作的经验很少,最终的命令是:

find "path1" -size 0 -printf "%f\0" | xargs -0 --max-args=1 --verbose find "path2" -exec ls -l {} \\\; -name

作为--verbose,我看到命令运行为

find path -exec ls -l {} \; -name foundfilename

和输出missing argument to exec

如果我xargs直接运行生成的命令构建(由于某种原因添加双引号 xargs --verbose 输出丢失,但显然在实践中使用,因为 find 不存在包含空格的路径问题:

find "path" -exec ls -l {} \; -name foundfilename

输出看起来像path.

  1. 为什么 xargs 和直接运行的结果不同find
  2. 看起来-exec不能先于-name,这是正确的吗?
  3. 最后说到重点:如何正确地find在另一个上运行结果find

系统:Linux Mint 19.2

在评论后添加以澄清第二个问题:

如果我跑

find "path" -name foundfilename -exec ls -l {} \;

我得到了按预期找到并列出的几个文件的输出ls,即第二个问题。

我测试了两个名为12的文件的设置/media/ramdrive

marina@tpx:~$ find /media/ramdrive -exec ls {} \; -name 1
1  2
/media/ramdrive/2
/media/ramdrive/1
marina@tpx:~$ find /media/ramdrive -name 1 -exec ls {} \;
/media/ramdrive/1

男子发现:

-执行命令;执行命令;如果返回 0 状态则为 true。 find 的所有以下参数都被视为命令的参数,直到由;' is encountered. The string{}' 组成的参数被当前文件名替换,该文件名出现在命令的参数中,而不仅仅是在单独的参数中,如在 find 的某些版本中。这两种结构可能都需要转义(用 '')或引用,以保护它们免受 shell 的扩展。有关使用 -exec 选项的示例,请参阅示例部分。对于每个匹配的文件,指定的命令运行一次。该命令在起始目录中执行。使用 -exec 操作存在不可避免的安全问题;您应该使用 -execdir 选项。

我不明白为什么-exec不能在匹配选项之前。

实际上我不明白“它出现在命令参数中的任何地方,而不仅仅是出现在它单独的参数中”的含义。

添加两个:
我虽然找到了解决方案:

find "path1" -size 0 -printf "%f\0" | xargs -0 --max-args=1 --verbose find "path2" -name | xargs ls -l

但 find 的默认打印不引用结果,因此对于带有空格的路径失败。是否有添加引号的实用程序?

答案1

为什么xargs和直接find运行结果不同?

当你类型 find path -exec ls -l {} \; -name foundfilename在 shell 中,shell 读\;作“传递;给命令”。如果只是;键入,它将是命令分隔符。反斜杠被 shell“吃掉”并改变其有关 的行为;

什么时候xargs说的运行 find path -exec ls -l {} \; -name foundfilename,它实际上传递\;给命令(即传递给find),没有 shell 来去除反斜杠。所以\;这里是错误的:-exec期望;+,它两者都得不到,因此“缺少 exec 的参数”。


看起来-exec不能先于-name,这是正确的吗?

不正确。它可以。也许不应该,这取决于你想做什么。两个命令的不同结果很容易解释。这两个命令是:

find /media/ramdrive -exec ls {} \; -name 1
find /media/ramdrive -name 1 -exec ls {} \;

重要事实:

  • -exec也是一种考验。当且仅当内部命令返回时,它就会成功0
  • 测试由运算符连接:(-o逻辑 OR)或-a(逻辑 AND)。-a假设缺少运算符(如您的情况) 。
  • 使用-test1 -o -test2-test1 -a -test2-test1首先进行测试。如果结果仅由其确定,-test1-test2不会执行。特别是,这意味着当且仅当成功时-test1 -a -test2才会运行(如果失败则不需要,因为我们已经知道结果:失败)。test2-test1-test2

如果您的总体测试是-exec ls {} \; -name 1(即-exec ls {} \; -a -name 1),则-exec对每个候选人进行测试。这已经将一些内容打印到标准输出。对于每个候选者都ls成功,则执行另一个测试;但这并不重要,因为其他测试不打印任何内容,并且没有进一步的测试/操作(默认值-print被 previous 抑制-exec)。

如果您的总体测试是-name 1 -exec ls {} \;(即-name 1 -a -exec ls {} \;),则-name对每个候选人进行测试。测试不打印任何内容,但其结果决定是否-exec执行。所以ls运行 iff-name成功,它会打印一些 iff-name成功的内容。


如何正确运行find另一个结果find

可以find-exec另一个内部运行find。例如,这会找到名为 的目录中的所有符号链接lib

find / -type d -name lib -exec find {} -type l \;

/lib/您可以从、等获得结果/var/lib//usr/lib/

有几个问题:

  • 这会find根据外部的一个结果运行一个内部find。如果您想一次使用一个结果的所有结果find,即使用单身的其他find
  • 如果内部find也需要运行-exec,则没有直接的方法可以将{}, ;(键入为\;) 或+传递给它,因为这些将由外部 解释find。一种解决方案是使用xargs(和你做到了),通常需要非 POSIX 选项才能使其对于包含换行符的名称不会失败。另一个解决方案是在两个finds 之间生成一个 shell(如这个另一个答案这是我在写我的文章时出现的,我不会重复它的解决方案)。

我不明白“它出现在命令参数中的任何地方,而不仅仅是出现在单独的参数中”的含义。

POSIX需要find扩展独自的 {}。对于类似{}.txt或“是替换这两个字符还是使用不改变的字符串foo{}bar是实现定义的”的参数。find您的版本find将替换为or{}之类的参数,并且手册明确说明了这一点。{}.txtfoo{}bar

答案2

做就是了:

find path1 -size 0 -exec sh -c '
  for file do
    find path2 -name "${file##%/}" -exec ls -ld \{\} +
  done' sh {} +

(假设空文件的名称都不包含通配符或反斜杠,则将-name其参数视为通配符模式)。

由于您find是来自 GNU 的,因此您也可以替换-exec ls -ld \{\} +-ls(既不-printf-ls标准的,但虽然-printf是 GNU 特定的,-ls但更便携,尽管不同实现之间的输出格式略有不同)。

更一般地,除非您使用 GNU 样式并输出 NUL 分隔的记录(例如使用或您的记录),否则您不想通过管道将findinto的输出进行传输。在大多数情况下,使用比管道到更好。更普遍,xargsxargs -r0find-print0-printf '%f\0'-exec ... {} +xargs卡米尔的回答很好地解释了你的方法中的问题,我在这里不再重复。

在这里,您可以使用zshshell 来代替:

for file (path1/**/*(NDL0)) ls -ld path2/**/$file:t(DN)

(不存在通配符问题)

答案3

-I按照 @muru 的提示在 中使用xargs,工作命令(假设find和的 GNU 实现xargs)是:

find "path1" -size 0 -printf "%f\0" |
  xargs -r0 -I mystr find "path2" -name mystr -exec ls -ld {} +

(假设空文件的名称不包含通配符,因为-name将其参数解释为通配符模式

相关内容