根据文件类型和日期查找并移动目录

根据文件类型和日期查找并移动目录

我有一个目录“New Movies”,其中包含 200 多个子目录“电影名称(年份)”。子目录“电影名称(年份)”包含一个视频文件(avi/mkv)和几个相关的 jpg/xml 文件。

我需要将包含至少 180 天的视频文件的所有目录移动到另一个目录。

例如:

新电影/电影 A(年)将包含 movie.mkv、folder.jpg 和 movie.xml,我想将它们移动到其他地方的同名子目录,并且所有文件都存在且完好无损。

在本网站的其他地方查看后,我尝试过:

cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 -exec sh -c 'mv "${0%/*}" /mnt/user/Movies' {} \;

该命令成功地将第一个子目录和所有文件移动到新目录,但是此后的每个操作都会返回错误

find: './Movie B (year)': No such file or directory
find: './Movie C (year)': No such file or directory

依此类推,浏览“新电影”下包含的所有目录,无论它们是否要移动。

答案1

不要-exec mv当前正在检查的目录findfind当你这样做时,似乎会感到困惑。

解决方法:首先找到目录,然后移动它们。

cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 \
  -printf "%h\0" | xargs -0 mv -t /mnt/user/Movies

解释:

  • -printf根据格式字符串打印匹配项。
  • %h打印匹配的路径部分。这对应于"${0%/*}"您命令中的 。
  • \0使用空字符分隔项目。这只是为了防止文件名包含换行符。
  • xargs从管道收集输入,然后执行附加输入的参数。
  • -0告诉 xargs 期望输入以空分隔而不是换行分隔。
  • mv -t <target>允许mv在调用时将所有源参数附加在末尾。

请注意,这仍然不是绝对安全的。一些奇怪的调度程序计时与管道缓冲区相结合仍然可能导致在移出目录mv之前执行。find为了防止这种情况,你可以这样做:

cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 \
  -printf "%h\0" > dirstomove
xargs -0 mv -t /mnt/user/Movies < dirstomove

背景说明:

我想你的情况find如下:

  1. find遍历目录/mnt/user/New Movies/。在那里,它会记录其缓存中的可用目录。
  2. find使用系统调用遍历到子目录之一chdir(subdirname)
  3. 在里面find找到一个通过过滤器的电影文件。
  4. findmv使用给定的参数执行。
  5. mv将目录移动到/mnt/user/Movies.
  6. find使用系统调用返回父目录chdir(..),该调用现在指向/mnt/user/Movies而不是/mnt/user/New Movies/
  7. find很困惑,因为它找不到之前记下的目录并抛出很多错误。

这个假设是基于这个问题的答案:find -exec mv 在第一次执行后停止。我不知道为什么find在这种情况下会停止工作并在您的情况下抛出错误。不同版本的find可能是解释。

答案2

设置IFS环境变量,IFS=$(echo -en "\n\b");以便外壳程序将根据换行符而不是空格来分隔项目。

此外,这-exec sh -c 'mv "${0%/*}" /mnt/user/Movies' {} \;也很奇怪。如果我没记错的话简化为-exec mv {} /mnt/user/Movies \;

相关内容