为什么“find / -name '*.txt' | cp /junk”不起作用?

mic*_*ope 0 pipe find xargs cp

如果我想找到名称中带有 .txt 的任何文件,并且对于找到的每个匹配项,将其复制到 /junk 文件夹中,以下内容可以被认为是有效的;

find / -name "*.txt" | cp /junk
Run Code Online (Sandbox Code Playgroud)

但这不会起作用,因为 find 会将结果作为列表生成,无法将其输入 cp。

所以我可以使用 xargs 来解决这个问题

find / -name "*.txt" | xargs cp /junk
Run Code Online (Sandbox Code Playgroud)

因为 xargs 会将列表更改为可以输入 cp 的一行。我还认为这个命令将完全完成文件搜索,“生成列表”,然后它才会运行管道的右侧(副本)。

或者(最好)我可以使用 exec

find / -name ".txt" -exec cp {} /junk \;
Run Code Online (Sandbox Code Playgroud)

每次找到匹配项时都会运行副本(并且它将在单独的进程中运行副本,因此 find 命令将继续并行运行)。

有人可以确认这些命令和我的理解是正确的吗?

我应该补充一点,这仅用于教育目的,这不是现实生活中的场景。

Luc*_*cas 7

  1. 是的,find / -name "*.txt" | cp /junk不会工作,因为cp不从标准输入读取它的参数。
  2. 不,find / -name "*.txt" | xargs cp /junk也不会工作,因为xargs将从 stdin 读取的参数附加到命令中,因此cp会尝试以错误的方向复制。(您可以尝试使用-I选项来解决该问题,xargs然后您可以简单地使用find -exec。)
  3. 是的,find / -name ".txt" -exec cp {} /junk \;会工作,但会对cp每个文件使用一次调用(并且会在找到文件后立即启动该命令)。

你也可以试试这个解决方案,我应该只启动一个调用cp(或者至少它会尽可能少地启动,命令行长度是有限的):

find / -path /junk -prune -or -name '*.txt' -print0 | xargs -0 sh -c 'cp "$@" /junk'
Run Code Online (Sandbox Code Playgroud)

正如@don_chrissti 评论的那样,cp -t如果您拥有 GNU cp,则可以使用。然后可以像这样完成

find / -path /junk -prune -or -name '*.txt' -print0 | xargs -0 cp -t /junk
Run Code Online (Sandbox Code Playgroud)

甚至

find / -path /junk -prune -or -name '*.txt' -exec cp -t /junk {} +
Run Code Online (Sandbox Code Playgroud)

所有这三个都将在命令行上收集尽可能多的参数并执行尽可能少的实例cp。但是可能仍然存在 acp在find完成之前启动的情况,因此我们必须排除,/junk否则它可能会找到副本。