我正在寻找一种方法(最好是终端)来按首字母组织超过 1000 种字体。
基本上,创建目录A-Z, #
,然后根据字体文件的文件名首字符将其移动到这些目录中。以数字 [0-9] 或其他特殊字符开头的字体将被移动到目录中#
。
答案1
一个较晚的 Python 选项:
#!/usr/bin/env python3
import os
import sys
import shutil
def path(dr, f): return os.path.join(dr, f)
dr = sys.argv[1]
for f in os.listdir(dr):
fsrc = path(dr, f)
if os.path.isfile(fsrc):
s = f[0]; target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
if not os.path.exists(target):
os.mkdir(target)
shutil.move(fsrc, path(target, f))
如何使用
- 将脚本复制到一个空文件中,另存为
move_files.py
使用目录作为参数运行它:
python3 /path/to/move_files.py /path/to/files
脚本仅在实际需要时才会创建(子)目录(大写)
解释
剧本:
列出文件,获取第一个字符(定义源路径):
for f in os.listdir(dr): s = f[0]; fsrc = path(dr, f)
检查该项目是否是文件:
if os.path.isfile(fsrc):
定义目标文件夹,判断第一个字符是否为字母:
target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
检查文件夹是否已经存在,如果不存在则创建该文件夹:
if not os.path.exists(target): os.mkdir(target)
将该项目移动到其相应的文件夹中:
shutil.move(fsrc, path(target, f))
答案2
仅使用两个命令和两个正则表达式即可编写代码且易于阅读:
mkdir -p '#' {a..z}
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|' [[:alnum:]]?*
如果您有大量文件需要移动,多到无法放入进程参数列表中(是的,有一个限制,可能只有几千字节),您可以使用不同的命令生成文件列表并将其通过管道传输到prename
,例如:
find -mindepth 1 -maxdepth 1 -name '[[:alnum:]]?*' -printf '%f\n' |
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|'
[[:alnum:]]?*
这还有一个好处,就是如果没有文件与 glob 模式匹配,则不会尝试移动文字文件名。还允许find
比 shell 通配符更多的匹配条件。另一种方法是设置nullglob
shell 选项并关闭 的标准输入流prename
。1
在这两种情况下,删除-n
开关实际上就是移动文件,而不仅仅是显示如何移动它们。
附录:您可以使用以下命令再次删除空目录:
rmdir --ignore-fail-on-non-empty '#' {a..z}
1 shopt -s nullglob; prename ... <&-
答案3
如果您不介意 zsh,一个函数和几个zmv
命令:
mmv() {echo mkdir -p "${2%/*}/"; echo mv -- "$1" "$2";}
autoload -U zmv
zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'
该mmv
函数创建目录并移动文件。zmv
然后提供模式匹配和替换。首先,移动以字母开头的文件名,然后移动其他所有内容:
$ zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
mkdir -p A/
mv -- abcd.ttf A/abcd.ttf
mkdir -p A/
mv -- ABCD.ttf A/ABCD.ttf
$ zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'
mkdir -p #/
mv -- 123.ttf #/123.ttf
mkdir -p #/
mv -- 七.ttf #/七.ttf
再次运行(不使用echo
inmmv
的定义)来真正执行移动。
答案4
包含字体的目录中的以下命令应该有效,如果您想从字体存储目录之外使用,请更改for f in ./*
为for f in /directory/containing/fonts/*
。这是一种非常基于 shell 的方法,因此速度很慢,并且也是非递归的。如果存在以匹配字符开头的文件,这将仅创建目录。
target=/directory/to/store/alphabet/dirs
mkdir "$target"
for f in ./* ; do
if [[ -f "$f" ]]; then
i=${f##*/}
i=${i:0:1}
dir=${i^}
if [[ $dir != [A-Z] ]]; then
mkdir -p "${target}/#" && mv "$f" "${target}/#"
else
mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir"
fi
fi
done
再次从字体存储目录中执行一行代码:
target=/directory/to/store/alphabet/dirs; mkdir "$target" && for f in ./* ; do if [[ -f "$f" ]]; then i=${f##*/}; i=${i:0:1} ; dir=${i^} ; if [[ $dir != [A-Z] ]]; then mkdir -p "${target}/#" && mv "$f" "${target}/#"; else mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir" ; fi ; fi ; done
一种使用 find 的方法,具有类似的字符串操作,使用 bash 参数扩展,它将是递归的,并且应该比纯 shell 版本更快一些:
find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs ; mkdir -p "$target"; f="{}" ; i="${f##*/}"; i="${i:0:1}"; i=${i^}; if [[ $i = [[:alpha:]] ]]; then mkdir -p "${target}/$i" && mv "$f" "${target}/$i"; else mkdir -p "${target}/#" && mv "$f" "${target}/#"; fi' \;
或者更易读的是:
find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs
mkdir -p "$target"
f="{}"
i="${f##*/}"
i="${i:0:1}"
i=${i^}
if [[ $i = [[:alpha:]] ]]; then
mkdir -p "${target}/$i" && mv "$f" "${target}/$i"
else
mkdir -p "${target}/#" && mv "$f" "${target}/#"
fi' \;