我正在尝试在 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" \;
这似乎非常接近,除了{}
没有被传递$2
到-exec sh -c ...
我想尽可能接近“正确的方式”,并容忍文件名中的特殊字符(特别是单引号字符)。
编辑:我看到有人建议使用xargs
或参数链。我的印象是,这只适用于有限数量的参数。例如,如果我有数千个 .jpg 文件,我试图从多个图库目录复制到一个巨大的幻灯片目录中,那么链接参数的解决方案仍然有效吗?
编辑2:_
我的问题是我在命令中的第一个选项 sh 之前缺少了 a -exec
。对于任何对如何使 find 命令起作用感到好奇的人,添加 ,_
一切都会好起来的:
find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;
我接受了下面的答案,因为它完成了相同的任务,但更高效和优雅。
答案1
您想将特定类型的文件复制到特定目录吗?最好这样做xargs
,而且您甚至不需要它sh
。这是一个比较合适的做法,也应该运行得更加高效。
find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir
如果您需要处理特殊文件名,请使用NULL
作为分隔符
find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"
答案2
您需要将{}
其作为参数传递给 shell,然后循环遍历每个参数。
find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +
笔记:它的工作方式是 shell 的第一个参数是外壳名称,我们可以通过将名称作为 the 传递,然后使用shell 脚本中的$targetdir
特殊参数来访问该目标目录来利用这一点。$0
答案3
如果你不相信 xargs 教会:
find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +
解释:
cp -t a b c d
将 b、c 和 d 复制到目标目录 a。
-exec cmd {} +
一次对一大堆文件调用该命令,而不是一个接一个地调用(这是标准的,如果您使用";"
而不是+
)。这就是为什么我们必须将 targetdir 拉到前面并将其显式标记为目标。
这适用于 gnu-find,但可能不适用于 find 的其他实现。当然它也依赖于 -t -标志。
TechZilla 当然位于最右边,因为sh
不需要调用 cp。
如果您不使用xargs
,大多数情况下不需要与 结合使用find
,那么您就无需学习-print0
和-0
标志。
答案4
read -p "SOURCE: " sourcedir
read -p "TYPE: " type
read -p "TARGET: " targetdir
find -L $sourcedir -iname "*.$type" -exec cp -v {} $targetdir \;