将 find 与其他命令结合使用:何时使用 -exec 以及何时使用管道?

yos*_*rry 7 command-line terminal find

我已经学会了单独使用 find 命令来查找文件和目录,但是当涉及到对文件/文件夹执行某些操作时,我感到很困惑。

给出以下命令:

find . -type f -iname "*.cr2" 
Run Code Online (Sandbox Code Playgroud)

如果我想将上面找到的那些文件复制到一个新目录中,我自然会认为使用 copy( cp) 和 pipe |

find . -type f -iname "*.cr2" | cp \destination_directory
Run Code Online (Sandbox Code Playgroud)

对我来说,这将使我所有的照片跨越整个驱动器,并嵌套在子文件夹的级别中,放入一个准备开始组织的文件夹中。

但是人们一直告诉我使用该-exec参数,所以我的问题是您如何知道何时使用管道|以及何时使用-exec如下命令?

 find . -name "*.pdf" -type f -exec cp {} ./pdfsfolder \;
Run Code Online (Sandbox Code Playgroud)

编辑

建议的解决方案(如下)仅复制文件名唯一的文件。它说cp不会复制file.txt并替换为file.txt。在你复制很多文件的情况下,不知道是否会有同名的文件,如果文件名存在,你如何复制并重命名它?

建议的解决方案

find . -type f -iname "*.txt" -print0 | xargs -0 cp -t /home/josh/Documents/copy/
Run Code Online (Sandbox Code Playgroud)

/home/josh/documents/copy 是我要将内容移动到的目录。

Ant*_*hon 12

您的假设存在错误,但首先要了解一些背景:

您应该辨别 的两种用途-exec

  • \;{} 会由单一发现商品被替换
  • +{}会由许多项目来替换(多达命令行可以容纳)。

因此,您的-exec使用示例调用的cp命令与find.

usingfind ... -exec cmd {} ... +在效率上与将 find 的输出管道传输到处理多个输入名称的命令中的效率相似。

您还应该考虑到它可以-exec很好地处理带有空格的文件名/路径,但是当您将输出从 find 管道传输到另一个可能会导致问题的程序时。因此,一些需要来自 stdin 的文件名列表的程序可以选择将这些文件名 NUL 分隔(通常-0--null)。并且find可以选择通过指定以下方式将它们提供给下一个程序:-print0


现在来看看你的例子:

find . -type f -iname "*.cr2" | cp destination_directory
Run Code Online (Sandbox Code Playgroud)

不复制找到的文件,因为 cp 不从标准输入读取。你将不得不使用:

find . -type f -iname "*.cr2" | xargs cp -t destination_directory
Run Code Online (Sandbox Code Playgroud)

或处理带空格的路径:

find . -type f -iname "*.cr2" -print0 | xargs -0 cp -t destination_directory
Run Code Online (Sandbox Code Playgroud)

以大致相同的效率,您可以执行以下操作:

find . -type f -iname "*.cr2" -exec cp -t destination_directory {} +
Run Code Online (Sandbox Code Playgroud)

(正如 G-Man 指出的那样{},必须在最后,在 之前+)以上所有内容都没有为此在目标目录下构建层次结构,并且即使源目录是扁平的,出于长期习惯,我发现自己使用cpio反而:

find . -type f -iname "*.cr2" -print0 | cpio -pdmv0 destination_directory
Run Code Online (Sandbox Code Playgroud)

它很好地列出了它在此过程中所做的事情。


相关部分来自man find

-exec command ;
       Execute command; true if 0 status is returned.   All  following
       arguments  to  find  are  taken  to be arguments to the command
       until an argument consisting of `;' is encountered.  The string
       `{}'  is  replaced  by  the  current  file name being processed
       everywhere it occurs in the arguments to the command, not  just
       in  arguments  where  it is alone, as in some versions of find.
       Both of these constructions might need to be  escaped  (with  a
       `\')  or  quoted  to  protect them from expansion by the shell.
       See the EXAMPLES section for examples of the use of  the  -exec
       option.   The  specified  command  is run once for each matched
       file.  The command  is  executed  in  the  starting  directory.
       There  are unavoidable security problems surrounding use of the
       -exec action; you should use the -execdir option instead.

-exec command {} +
       This variant of the -exec action runs the specified command  on
       the  selected files, but the command line is built by appending
       each selected file name at the end; the total number of invoca?
       tions  of  the  command  will  be  much less than the number of
       matched files.  The command line is built in much the same  way
       that xargs builds its command lines.  Only one instance of `{}'
       is allowed within the command.  The command is executed in  the
       starting directory.
Run Code Online (Sandbox Code Playgroud)