![如何编写一个 shell 脚本来根据文件名将文件移动到单独的文件夹中?](https://linux22.com/image/1169153/%E5%A6%82%E4%BD%95%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AA%20shell%20%E8%84%9A%E6%9C%AC%E6%9D%A5%E6%A0%B9%E6%8D%AE%E6%96%87%E4%BB%B6%E5%90%8D%E5%B0%86%E6%96%87%E4%BB%B6%E7%A7%BB%E5%8A%A8%E5%88%B0%E5%8D%95%E7%8B%AC%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%AD%EF%BC%9F.png)
我想自动将电视节目剧集文件移动到每集的单独目录中。
本质上,在我想要运行脚本的文件夹中,我有一个文件列表。例如:tvshow.2009.S01E01.episodename1.mkv
、、、 等。以及格式为、、、等tvshow.2009.S01E02.episodename2.mkv
的空目录。tvshow.2009.S01E03.episodename3.mkv
E01
E02
E03
此时,我一直在借助Tab命令行的自动完成功能手动移动文件。基本上,我输入的是:
mv t
然后按下Tab自动完成键
mv tv.show.2009.S01E0
然后再次输入1
并Tab进入
mv tv.show.2009.S01E01.episodename1.mkv
然后我输入正确的文件夹来访问
mv tv.show.2009.S01E01.episodename1.mkv E01/
然后点击Enter完成命令。我必须对原始目录中的剧集重复这些步骤,鉴于我本质上是在重复相同的步骤,只是迭代剧集编号,这似乎是脚本中 for 循环的完美用法。
问题是,文件的格式并不总是相同的,而且显然会根据节目的不同而有不同的名称。但不变的是S##E##
,总是出现在文件名中,我只需要使用E##
来识别正确的文件并将其移动到已经存在的文件夹中,然后完全匹配来自E##
文件。
我是一名经验丰富的程序员,但还没有使用过 shell 脚本。我的想法是遍历所有现有E##
文件夹,查找包含该E##
序列的文件,然后将该文件移动到文件夹中。不幸的是,我不确定使用可以在命令行上运行的脚本执行此操作的正确方法。
有人能建议一下解决方法或者给我指出可以参考的资源来寻求帮助吗?
答案1
这是我根据其他答案想出的解决方案
#!/bin/bash
for f in *.mkv *.mp4 *.wmv; do
if [ -f "$f" ] # does file exist?
then
dir=$(echo "$f" | grep -o "E[0-9][0-9]" | head -1) # extract first E## from filename
if [ "$dir" ] # check if string found
then
mkdir -p "$dir" # create dir
mv "$f" "$dir" # move file into new dir
else
echo "INCORRECT FILE FORMAT: \""$f"\"" # print error if file format is unexpected
fi
fi
done
我必须添加一些错误检查来捕获任何格式不正确的文件,以及文件名有两个匹配的 E## 字符串(例如tvshow.S01E20E21.mkv
)的双集文件。对于双集文件,它将仅为第一个集号创建一个目录,并将文件移动到那里。请注意,此脚本也会创建目录,E##
因为这样更容易让一个脚本完成所有工作。
答案2
在我看来,你只是想把所有 E01 复制到 E01 文件夹中,把 E02 复制到 E02 文件夹中等等,如果是这种情况,那么像这样的 bash 脚本应该可以工作
#!/bin/bash
cd $(dirname $0)
for orig_filename in ./mkvfiles/*.mkv; do
dirname="$(dirname $orig_filename)"
filename=${orig_filename##*/}
series=${filename%.*}
episode=${orig_filename}
[[ $episode =~ [eE][0-9][0-9] ]]
epi="${BASH_REMATCH[0]}"
if [ -n "$epi" ]; then
echo ${epi^^}
[ ! -d ${epi^^} ] && mkdir -p ${epi^^} || :
/bin/cp $orig_filename ${epi^^}/$filename
fi
done
该脚本只是迭代所有文件,过滤 Exx(其中 xx 是数字)并创建/复制文件到相关文件夹。
您可能还需要更改 ./mkvfiles/*.mkv
答案3
您可以在文件所在目录和空目录下使用它,假设您的文件具有.mkv
扩展名:
for file in *.mkv;do mv "$file" "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')";done
在上面的for
循环中,mv
用于将每个文件 ( "$file"
) 移动到相应的剧集目录 ( "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')"
)。这里,sed
用于从文件名中提取剧集。本质上,它S##E##
使用正则表达式 ( .*S[0-9]+(E[0-9]+).*
) 匹配文件名的部分,其中只保留括号内的部分(\1
在命令末尾sed
)。
初始文件结构:
.
├── E01
├── E02
├── E03
├── E04
├── E05
├── tv.show.2009.S01E01.episodename1.mkv
├── tv.show.2009.S01E02.episodename1.mkv
├── tv.show.2009.S01E03.episodename1.mkv
├── tv.show.2009.S01E04.episodename1.mkv
└── tv.show.2009.S01E05.episodename1.mkv
结果:
.
├── E01
│ └── tv.show.2009.S01E01.episodename1.mkv
├── E02
│ └── tv.show.2009.S01E02.episodename1.mkv
├── E03
│ └── tv.show.2009.S01E03.episodename1.mkv
├── E04
│ └── tv.show.2009.S01E04.episodename1.mkv
└── E05
└── tv.show.2009.S01E05.episodename1.mkv
虽然您提到您已经创建了剧集目录,但您可以创建它们,并通过修改上面的命令移动其中的文件。修改只是添加mkdir "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')"
到命令中(echo
部分与之前相同mv
)。因此,创建目录并移动其中的文件的命令是:
for file in *.mkv;do mkdir "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')" && mv "$file" "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')";done
初始文件结构:
.
├── tv.show.2009.S01E01.episodename1.mkv
├── tv.show.2009.S01E02.episodename1.mkv
├── tv.show.2009.S01E03.episodename1.mkv
├── tv.show.2009.S01E04.episodename1.mkv
└── tv.show.2009.S01E05.episodename1.mkv
结果:
.
├── E01
│ └── tv.show.2009.S01E01.episodename1.mkv
├── E02
│ └── tv.show.2009.S01E02.episodename1.mkv
├── E03
│ └── tv.show.2009.S01E03.episodename1.mkv
├── E04
│ └── tv.show.2009.S01E04.episodename1.mkv
└── E05
└── tv.show.2009.S01E05.episodename1.mkv
答案4
我认为,这或多或少可以为你提供帮助:
#!/bin/bash
for f in *.mkv *.mp4 *.wmv; do # add the extensions you want
dir=$(echo "$f" | grep -o "S[0-9][0-9]E[0-9][0-9]")
mkdir -p $dir
mv $f $dir
done
如果您只想运行一次脚本,您可以将文件夹的路径复制到一个文件中,我们称之为list
:
/path/to/seriesX
/path/to/seriesY
/path/to/seriesZ
然后在“根”文件夹中执行脚本:
#!/bin/bash
mapfile -t array < list
for d in "${array[@]}"; do
for f in "$d"/*.mkv; do
dir="$(echo "$f" | grep -o "S[0-9][0-9]E[0-9][0-9]")"
mkdir -p "$d"/"$dir"
mv "$f" "$d"/"$dir"/
done
done