查找和复制包含文件类型的目录

Low*_*wey 4 directory find cp recursive files

我有一个目录“电影”,其中包含子目录“电影名称”。每个子目录“电影名称”包含一个电影文件和相关的图像/信息文件等。

我正在尝试将包含“.avi”类型的电影文件的所有目录复制到外部 USB 设备。

因此,如果Directory/subdirectory A包含movie.avi, poster.jpgmovie.nfo,那么我想将该目录及其内容复制到外部驱动器。

我试过这个:

find . -name "*.avi" -printf "%h\n" -exec cp {} /share/USBDisk1/Movies/ \;
Run Code Online (Sandbox Code Playgroud)

但它只复制文件,而不复制目录和文件内容。

Gil*_*il' 5

首先,为什么您的尝试不起作用:-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)

请注意,由于您正在复制目录,因此您需要传递-rcp。您也应该保留元数据,例如文件的修改时间,使用-p.

您可以有用地替换cp -Rprsync -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)