Mat*_*hew 14 bash find shell-script posix
我正在尝试在 bash 脚本中运行类似于以下命令的命令。它应该搜索所有子文件夹$sourcedir
并将特定类型的所有文件复制到$targetdir
.
#!/bin/bash
# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;
Run Code Online (Sandbox Code Playgroud)
这似乎非常接近,除了{}
没有被传递$2
到-exec sh -c ...
我想尽可能接近“正确的方式”,并容忍文件名中的特殊字符(特别是单引号字符)。
编辑:我看到有人建议使用xargs
或参数链接。我的印象是这仅适用于有限数量的参数。例如,如果我有数以千计的 .jpg 文件,我试图从多个画廊目录复制到一个巨大的幻灯片目录中,那么链接参数的解决方案是否仍然有效?
编辑 2:我的问题是我_
在-exec
命令中的第一个选项 sh 之前缺少一个。对于任何对如何使 find 命令工作感到好奇的人,添加_
,一切都会好起来的:
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;
Run Code Online (Sandbox Code Playgroud)
我已经接受了下面的答案,因为它完成了相同的任务,但更高效和优雅。
您需要将{}
参数作为参数传递给 shell,然后循环遍历每个 arg。
find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +
Run Code Online (Sandbox Code Playgroud)
注意:这样做的方式是,shell 的第一个 arg 是 shell 的名称,我们可以通过将名称作为 the 传递$targetdir
,然后使用$0
shell 脚本中的特殊参数来访问该目标目录来利用这一点。
您想将特定类型的文件复制到特定目录?这最好用 完成xargs
,你甚至不需要那个sh
。这是一种更合适的方式来做到这一点,也应该更有效地运行。
find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir
Run Code Online (Sandbox Code Playgroud)
如果您需要处理特殊文件名,请NULL
用作分隔符
find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"
Run Code Online (Sandbox Code Playgroud)
如果你不相信 xargs 教会:
find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +
Run Code Online (Sandbox Code Playgroud)
解释:
cp -t a b c d
Run Code Online (Sandbox Code Playgroud)
将 b、c 和 d 复制到目标目录 a。
-exec cmd {} +
Run Code Online (Sandbox Code Playgroud)
一次对一大堆文件调用命令,而不是一个接一个地调用(这是标准的,如果您使用";"
代替+
)。这就是为什么必须将 targetdir 拉到前面并将其明确标记为目标的原因。
这适用于 gnu-find 并且可能不适用于 find 的其他实现。当然,它也依赖于 -t -flag。
TechZilla 当然是最正确的,因为sh
它不需要调用 cp。
如果您不使用xargs
,这在大多数情况下与 结合使用find
是不必要的,您就无需学习-print0
和-0
标志。