英文:
Creating folders based on part of a filename
问题
我在 macOS 上的一个文件夹中有一堆有声书。文件命名结构是 `作者 - 标题.m4b`(例如 `JRR Tolkien - 魔戒.m4b`)。我想运行一个 bash 脚本,然后得到以下文件夹结构:
- 作者(文件夹)
- --> 标题(文件夹)
- ----> 保持不变的有声书 m4b 文件(如上命名)
因此文件将位于作者文件夹中的书籍文件夹中。
我找到了这个脚本:
```bash
find . -type f -name "*jpg" -maxdepth 1 -exec bash -c 'mkdir -p "${0%%_*}"' {} \; \
-exec bash -c 'mv "$0" "${0%%_*}"' {} \;
但它“仅”将作者作为文件夹并将文件放在其中。我还没有找到一种方法来获取标题并将其作为另一子文件夹级别。
<details>
<summary>英文:</summary>
I have a bunch of audiobooks in one folder on macOS. The file naming structure is `Author - Title.m4b` (e.g. `JRR Tolkien - Lord of the Rings.m4b`). I would like to run a bash script and then have the following folder structure:
- Author (folder)
- --> Title (folder)
- ----> Audiobook m4b file (naming as above, unchanged)
So the file would be in the book folder in the author folder.
I have found this script:
find . -type f -name "*jpg" -maxdepth 1 -exec bash -c 'mkdir -p "${0%%_*}"' {} \; \
-exec bash -c 'mv "$0" "${0%%_*}"' {} \;
But it "only" takes the author as a folder and puts the file in there. I have not found a way to take the title and make this another subfolder level.
</details>
# 答案1
**得分**: 2
使用给定的文件名结构,结合 `sh`、`mkdir` 和 `mv`,类似以下方式:
```lang bash
#!/bin/sh
for file in ./*.m4b; do
author="${file%% *}"
file_name="${file##* }"
title="${file_name%.*}"
echo mkdir -p "$author/$title" &&
echo mv -v "$file" "$author/$title/$file_name"
done
输出:
mkdir -p ./Author/Title
mv -v ./Author - Title.m4b ./Author/Title/Title.m4b
去掉所有的 echo
后,在我的一侧输出如下:
renamed './Author - Title.m4b' -> './Author/Title/Title.m4b'
这应该处理带有空格的文件名。
#!/bin/sh
for file in ./*.m4b; do
author=${file%% -*}
file_name=${file##*- }
title=${file_name%.*}
echo mkdir -p "$author/$title" &&
echo mv -v "$file" "$author/$title/$file_name"
done
使用 bashv4+
和 =~
运算符。
#!/bin/bash
regexp='^(.+) - (.*)\.(.+)$'
for file in ./*.m4b; do
[[ $file =~ $regexp ]] &&
author=${BASH_REMATCH[1]}
title=${BASH_REMATCH[2]}
file_name=${BASH_REMATCH[2]}.${BASH_REMATCH[3]}
echo mkdir -p "$author/$title" &&
echo mv -v "$file" "$author/$title/$file_name"
done
输出:
mkdir -p ./Author/Title
mv -v ./Author - Title.m4b ./Author/Title/Title.m4b
mkdir -p ./Dan Brown/Diabolus
mv -v ./Dan Brown - Diabolus.m4b ./Dan Brown/Diabolus/Diabolus.m4b
mkdir -p ./JRR Tolkien/Lord of the Rings
mv -v ./JRR Tolkien - Lord of the Rings.m4b ./JRR Tolkien/Lord of the Rings/Lord of the Rings.m4b
去掉 echo
后:
renamed './Author - Title.m4b' -> './Author/Title/Title.m4b'
renamed './Dan Brown - Diabolus.m4b' -> './Dan Brown/Diabolus/Diabolus.m4b'
renamed './JRR Tolkien - Lord of the Rings.m4b' -> './JRR Tolkien/Lord of the Rings/Lord of the Rings.m4b'
从 tree
实用工具的输出:
Author/
└── Title
└── Title.m4b
Dan Brown/
└── Diabolus
└── Diabolus.m4b
JRR Tolkien/
└── Lord of the Rings
└── Lord of the Rings.m4b
3 directories, 3 files
- 如果你在与文件相同的目录中(相对路径)运行上述脚本,那么脚本将正常工作,否则请将
./*.m4b
更改为绝对路径。 - 参考 POSIX sh 参数扩展
- 参考 Bash Shell 参数扩展
英文:
With your given file name structure, with sh
, mkdir
and mv
something like this:
#!/bin/sh
for file in ./*.m4b; do
author="${file%% *}"
file_name="${file##* }"
title="${file_name%.*}"
echo mkdir -p "$author/$title" &&
echo mv -v "$file" "$author/$title/$file_name"
done
Output:
mkdir -p ./Author/Title
mv -v ./Author - Title.m4b ./Author/Title/Title.m4b
Without all the echo
, the output is like this on my side:
renamed './Author - Title.m4b' -> './Author/Title/Title.m4b'
This should handle your file names with spaces.
#!/bin/sh
for file in ./*.m4b; do
author=${file%% -*}
file_name=${file##*- }
title=${file_name%.*}
echo mkdir -p "$author/$title" &&
echo mv -v "$file" "$author/$title/$file_name"
done
with bashv4+
with the =~
operator.
#!/bin/bash
regexp='^(.+) - (.*)\.(.+)$'
for file in ./*.m4b; do
[[ $file =~ $regexp ]] &&
author=${BASH_REMATCH[1]}
title=${BASH_REMATCH[2]}
file_name=${BASH_REMATCH[2]}.${BASH_REMATCH[3]}
echo mkdir -p "$author/$title" &&
echo mv -v "$file" "$author/$title/$file_name"
done
Output:
mkdir -p ./Author/Title
mv -v ./Author - Title.m4b ./Author/Title/Title.m4b
mkdir -p ./Dan Brown/Diabolus
mv -v ./Dan Brown - Diabolus.m4b ./Dan Brown/Diabolus/Diabolus.m4b
mkdir -p ./JRR Tolkien/Lord of the Rings
mv -v ./JRR Tolkien - Lord of the Rings.m4b ./JRR Tolkien/Lord of the Rings/Lord of the Rings.m4b
Without the echo
renamed './Author - Title.m4b' -> './Author/Title/Title.m4b'
renamed './Dan Brown - Diabolus.m4b' -> './Dan Brown/Diabolus/Diabolus.m4b'
renamed './JRR Tolkien - Lord of the Rings.m4b' -> './JRR Tolkien/Lord of the Rings/Lord of the Rings.m4b'
- Remove all the
echo
if you're satisfied with the output.
Output from the tree
utility:
Author/
└── Title
└── Title.m4b
Dan Brown/
└── Diabolus
└── Diabolus.m4b
JRR Tolkien/
└── Lord of the Rings
└── Lord of the Rings.m4b
3 directories, 3 files
-
The script above works if you're inside the same directory as the files in question (relative path), otherwise change
./*.m4b
to its absolute path. -
See POSIX sh Parameter Expansion
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论