执行 find 命令后如何在 for 循环中使用 exec 命令?

Joh*_*ton 4 command-line bash find

我一直试图让这个工作一段时间。我想搜索文件列表,然后将它们全部复制到某个路径。

如果我单独运行该命令,则它的工作方式如下:

find <path> -name 'file1' -exec cp '{}' <path2> \;
Run Code Online (Sandbox Code Playgroud)

但是我一直无法在 for 循环中运行它。

#this works
for f in file1 file2 file3...; do find <path> -name "$f" \; done;
#none of these work (this code tries to find and copy the files named file and list from the path)
for f in file1 file2 file3...; do find <path> -name "$f" -exec cp '{}' <path2> \; done;
for f in file1 file2 file3...; do find <path> -name "$f" -exec cp {} <path2> \; done;
Run Code Online (Sandbox Code Playgroud)

我尝试了其他一些不太可能奏效的东西。代码引用中的第一行卡住了,其他人即使没有卡住也不会复制任何内容。

搜索后,我无法在 for 循环中使用 exec 运行任何内容,此时我不确定该怎么做。

我已经通过搜索文件并将结果记录到另一个文件,然后在 for 循环中单独运行副本解决了眼前的问题,但我仍然想知道如何做到这一点。

hee*_*ayl 7

两个问题:

  1. for f in some_file不迭代 的内容some_file,只是迭代或获取文字字符串some_file。为了克服这个忘记for循环迭代文件内容的问题,使用正确实现的while构造。

  2. '$f'在这种情况下,将变量放在单引号内时不会扩展。要使您的原始想法发挥作用,请使用双引号。

将这些放在一起,假设文件名在file_list文件内以换行符分隔:

while IFS= read -r f; do 
    find /path1 -name "$f" -exec cp '{}' /path2 \;
done <file_list
Run Code Online (Sandbox Code Playgroud)

或者,如果您知道文件将在该/path1目录中,而不是在它的任何子目录下,您可以只使用数组来获取文件名,并cp直接使用 (GNU) ,再次假设文件名内部有换行符file_list

( 
 IFS=$'\n'
 files=( $(<file_list) )
 cp -t /path2 "${files[@]}"
)
Run Code Online (Sandbox Code Playgroud)

在大量文件的情况下,最好cp单独迭代而不是转储到数组中:

while IFS= read -r f; do cp -- "$f" /path2; done <file_list
Run Code Online (Sandbox Code Playgroud)

如果file1 file2 file3 ...直接在for构造中有像 eg 这样的文件列表,那么只使用双引号就可以了:

for f in file1 file2 file3; do 
    find /path1 -name "$f" -exec cp '{}' /path2 \;
done
Run Code Online (Sandbox Code Playgroud)

现在,cp如果所有文件都不在任何子目录中,您也可以直接在此处使用:

cp -t /path2 file1 file2 file3
Run Code Online (Sandbox Code Playgroud)

或者您可以提供静态绝对或相对路径,以防您只想cp用于处理任何子目录下的任何文件。


Zan*_*nna 5

您澄清说您的文件列表不是文本文件,而是您希望使用find. 你提到这对你有用:

for f in file1 file2 file3 ... ; do find <path> -name "$f" \; done;
Run Code Online (Sandbox Code Playgroud)

大概您的意思是您从该命令中获得了预期的文件列表。

然后你说这不起作用:

for f in file1 file2 file3 ... ; do find <path> -name "$f" -exec cp '{}' <path2> \; done
Run Code Online (Sandbox Code Playgroud)

大概你的意思是前面列出的文件没有复制到<path2>. 我不确定您遇到了什么错误,但正如所写的那样,我希望该命令像这样挂起:

$for f in file1 file2 file3 ... ; do find <path> -name "$f" -exec cp '{}' <path2> \; done
>
Run Code Online (Sandbox Code Playgroud)

等待失踪;。假设你纠正了这个问题,我想不出你的命令肯定会失败的任何其他明显原因。你应该能够管理

for f in file1 file2 file3 ... ; do find <path> -name "$f" -exec cp '{}' <path2> \; ; done
Run Code Online (Sandbox Code Playgroud)

但是我建议使用-t标志来指定目录。我要感谢大卫·福斯特这个评论,我觉得表演的最佳形式的cpmv调用使用find。它也将拒绝覆盖重复文件。

for f in file1 file2 file3; do find /path/to/search -name "$f" -exec cp -vt /path/to/destination -- {} + ; done
Run Code Online (Sandbox Code Playgroud)

笔记

  • -v 详细点 - 告诉我们正在做什么
  • -t 使用指定的目录作为目标
  • -- 不接受任何进一步的选择
  • +如果有多个匹配项(在您的情况下这不太可能,因为for它将为文件列表中的每个项目运行一次,但每个名称可能有多个匹配的文件),然后构造一个参数列表cp而不是cp多次运行
  • ;在 shell 中分隔命令。for循环的形式是

    for var in things; do command "$var"; done
    
    Run Code Online (Sandbox Code Playgroud)

    如果没有看到;before done,bash 将等待;或中断信号。