Low*_*wey 4 directory find cp recursive files
我有一个目录“电影”,其中包含子目录“电影名称”。每个子目录“电影名称”包含一个电影文件和相关的图像/信息文件等。
我正在尝试将包含“.avi”类型的电影文件的所有目录复制到外部 USB 设备。
因此,如果Directory/subdirectory A
包含movie.avi
, poster.jpg
和movie.nfo
,那么我想将该目录及其内容复制到外部驱动器。
我试过这个:
find . -name "*.avi" -printf "%h\n" -exec cp {} /share/USBDisk1/Movies/ \;
Run Code Online (Sandbox Code Playgroud)
但它只复制文件,而不复制目录和文件内容。
首先,为什么您的尝试不起作用:-printf "%h\n"
打印.avi
文件名的目录部分。这不会影响后续-exec
操作中的任何内容——{}
并不意味着“无论最后printf
打印的命令是什么”,而是“找到文件的路径”。
如果要在该cp
命令中使用文件名的目录部分,则需要在将文件名传递给cp
. 该find
命令没有此功能,但 shell 有此功能,因此 makefind
调用一个调用cp
.
find . -name "*.avi" -exec sh -c 'cp -Rp "${0%/*}" /share/USBDisk1/Movies/' {} \;
Run Code Online (Sandbox Code Playgroud)
请注意,由于您正在复制目录,因此您需要传递-r
给cp
。您也应该保留元数据,例如文件的修改时间,使用-p
.
您可以有用地替换cp -Rp
为rsync -a
。这样,如果您已经复制了电影目录,则不会再次复制它(除非其内容已更改)。
你的命令有一个缺陷,可能会也可能不会影响你:如果一个目录包含多个.avi
文件,它将被多次复制。最好查找目录,如果它们包含.avi
文件,则复制它们,而不是查找.avi
文件。如果您使用rsync
代替cp
,则不会再次复制文件,只需一遍又一遍地rsync
验证文件是否存在,就需要做更多的工作。
如果所有电影目录都直接位于顶级目录下,则不需要find
,对通配符模式进行简单循环就足够了。
for d in ./*/; do
set -- "$d/"*.avi
if [ -e "$1" ]; then
# there is at least one .avi file in $d
cp -rp -- "$d" /share/USBDisk1/Movies/
fi
done
Run Code Online (Sandbox Code Playgroud)
如果电影目录可能是嵌套的(例如Movies/science fiction/Ridley Scott/Blade Runner
),则不需要find
,对通配符模式的简单循环就足够了。您确实需要运行 ksh93 或 bash ?4 或 zsh,在 ksh93 中您需要先运行set -o globstar
,而在 bash 中您需要先运行shopt -s globstar
。通配符模式**/
递归地匹配当前目录及其所有子目录(bash 还遍历到子目录的符号链接)。
for d in ./**/; do
set -- "$d/"*.avi
if [ -e "$1" ]; then
cp -rp -- "$d" /share/USBDisk1/Movies/
fi
done
Run Code Online (Sandbox Code Playgroud)