我对“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
.
- 为什么 xargs 和直接运行的结果不同
find
? - 看起来
-exec
不能先于-name
,这是正确的吗? - 最后说到重点:如何正确地
find
在另一个上运行结果find
?
系统:Linux Mint 19.2
在评论后添加以澄清第二个问题:
如果我跑
find "path" -name foundfilename -exec ls -l {} \;
我得到了按预期找到并列出的几个文件的输出ls
,即第二个问题。
我测试了两个名为1
和2
的文件的设置/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 选项才能使其对于包含换行符的名称不会失败。另一个解决方案是在两个find
s 之间生成一个 shell(如这个另一个答案这是我在写我的文章时出现的,我不会重复它的解决方案)。
我不明白“它出现在命令参数中的任何地方,而不仅仅是出现在单独的参数中”的含义。
POSIX需要find
扩展独自的 {}
。对于类似{}.txt
或“是替换这两个字符还是使用不改变的字符串foo{}bar
是实现定义的”的参数。find
您的版本find
将替换为or{}
之类的参数,并且手册明确说明了这一点。{}.txt
foo{}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 分隔的记录(例如使用或您的记录),否则您不想通过管道将find
into的输出进行传输。在大多数情况下,使用比管道到更好。更普遍,xargs
xargs -r0
find
-print0
-printf '%f\0'
-exec ... {} +
xargs
卡米尔的回答很好地解释了你的方法中的问题,我在这里不再重复。
在这里,您可以使用zsh
shell 来代替:
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
将其参数解释为通配符模式)