好吧,我有一个非常大的 iTunes 库,最近我决定对它进行分类和整理,而不是简单地将所有音乐放在一个文件夹中,然后希望得到最好的结果。经过几个小时的移动文件或目录,并等待 iTunes 完成它的工作后,不知何故,我最终丢失了几首歌曲。如果是 1 或 2 首,那又怎么样,我可以自己找到它们。但我丢失了 30000 多首歌曲,所以我不太想手动寻找它们。
所以我的问题是,“在 Linux 环境中,有没有办法找到 1 个目录中不在另一个目录中的所有文件,然后移动它们?”
我的文件夹结构看起来有点像这样:
父目录(外部硬盘)
- 丢失文件(有 4 个这样的文件夹
- 数百个带有艺术家姓名的文件夹(有些文件夹有 .mp3 文件,有些文件夹有另一个子文件夹,有些文件夹又有另一个子文件夹)
- 父级 iTunes 目录(iTunes 保存音乐、播放列表文件、播客等的位置)
- 丢失文件(有 4 个这样的文件夹
(我在这些问题中真的很不擅长列表^)所以我需要的是移动任何是在“丢失的文件”目录中不是在“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