将不同的文件移动到另一个文件夹

将不同的文件移动到另一个文件夹

好吧,我有一个非常大的 iTunes 库,最近我决定对它进行分类和整理,而不是简单地将所有音乐放在一个文件夹中,然后希望得到最好的结果。经过几个小时的移动文件或目录,并等待 iTunes 完成它的工作后,不知何故,我最终丢失了几首歌曲。如果是 1 或 2 首,那又怎么样,我可以自己找到它们。但我丢失了 30000 多首歌曲,所以我不太想手动寻找它们。

所以我的问题是,“在 Linux 环境中,有没有办法找到 1 个目录中不在另一个目录中的所有文件,然后移动它们?”

我的文件夹结构看起来有点像这样:

  • 父目录(外部硬盘)

    • 丢失文件(有 4 个这样的文件夹
      • 数百个带有艺术家姓名的文件夹(有些文件夹有 .mp3 文件,有些文件夹有另一个子文件夹,有些文件夹又有另一个子文件夹)
    • 父级 iTunes 目录(iTunes 保存音乐、播放列表文件、播客等的位置)

(我在这些问题中真的很不擅长列表^)所以我需要的是移动任何在“丢失的文件”目录中不是在“iTunes 文件夹”中

谢谢你们提前提供的任何帮助,我非常感激。

注意:我只想移动文件夹中的 mp3 文件,而不是文件夹本身。

答案1

假设您有一个如下目录结构:

music
  |- source
      |- foobar
      |- spamegg
      |- ...
  |- dest

并且仅当文件尚不存在时,您才需要将.mp3任何级别子目录下的所有文件移动到。music/source/music/dest/music/dest/

如果是这样,music/从目录运行以下所有命令

  • .mp3创建一个包含下所有文件的数组music/source,递归操作:

    shopt -s globstar  ## Enables recursive search
    source_files=( source/**/*.mp3 )
    
  • 对目录执行相同操作music/dest/,并从文件名中去掉目录部分:

    dest_files=( dest/**/*.mp3 )
    dest_files=( ${dest_files[@]} )
    
  • 迭代源文件并检查文件是否已经存在于目标中,如果不存在则mv文件为music/dest/

    for i in "${source_files[@]}"; do [[ ! ${dest_files[@]} =~ ${i##*/} ]] && \
             echo mv -i "$i" dest/; done 
    

    echo用于进行试运行,如果满意,则删除echo

    for i in "${source_files[@]}"; do [[ ! ${dest_files[@]} =~ ${i##*/} ]] && \
             mv -i "$i" dest/; done
    

脚本形式:

#!/usr/bin/env bash
shopt -s globstar
source_files=( source/**/*.mp3 )
dest_files=( dest/**/*.mp3 )
dest_files=( ${dest_files[@]} )
for i in "${source_files[@]}"; do [[ ! ${dest_files[@]} =~ ${i##*/} ]] && \
     mv -i "$i" dest/; done

您显然可以使用绝对路径,更改相关路径以满足您的需要。

注意事项:

  • 所有源文件和目标.mp3文件都放入数组中,需要一些额外的内存,在现代系统上应该不是问题

  • 会员资格测试需要时间,但在现代系统中并不引人注意

例子:

music$ tree 
.
├── dest
│   ├── 1.mp3
│   ├── 2.mp3
│   ├── 3.mp3
│   ├── 7.mp3
│   ├── 8.mp3
│   └── 9.mp3
└── source
    ├── bar
    │   ├── 10.mp3
    │   ├── 6.mp3
    │   ├── 7.mp3
    │   ├── 8.mp3
    │   └── 9.mp3
    └── foo
        ├── 1.mp3
        ├── 2.mp3
        ├── 3.mp3
        ├── 4.mp3
        └── 5.mp3

music$ shopt -s globstar

music$ source_files=( source/**/*.mp3 )

music$ dest_files=( dest/**/*.mp3 )

music$ dest_files=( ${dest_files[@]} )

music$ for i in "${source_files[@]}"; do [[ ! ${dest_files[@]} =~ ${i##*/} ]] && echo mv "$i" dest/; done
mv source/bar/10.mp3 dest/
mv source/bar/6.mp3 dest/
mv source/foo/4.mp3 dest/
mv source/foo/5.mp3 dest/

music$ for i in "${source_files[@]}"; do [[ ! ${dest_files[@]} =~ ${i##*/} ]] && mv "$i" dest/; done

music$ tree 
.
├── dest
│   ├── 10.mp3
│   ├── 1.mp3
│   ├── 2.mp3
│   ├── 3.mp3
│   ├── 4.mp3
│   ├── 5.mp3
│   ├── 6.mp3
│   ├── 7.mp3
│   ├── 8.mp3
│   └── 9.mp3
└── source
    ├── bar
    │   ├── 7.mp3
    │   ├── 8.mp3
    │   └── 9.mp3
    └── foo
        ├── 1.mp3
        ├── 2.mp3
        └── 3.mp3

相关内容