我正在寻找一种方法(最好是终端)来按首字母组织1000多种字体。
基本上创建目录,A-Z, #
然后根据文件名的第一个字符将字体文件移动到这些目录。以数字[0-9]或其他特殊字符开头的字体将被移动到#
目录中。
我正在寻找一种方法(最好是终端)来按首字母组织1000多种字体。
基本上创建目录,A-Z, #
然后根据文件名的第一个字符将字体文件移动到这些目录。以数字[0-9]或其他特殊字符开头的字体将被移动到#
目录中。
Answers:
较晚的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
该脚本仅在实际需要时才创建(子)目录(-ies)(大写)
剧本:
列出文件,获取第一个字符(定义源路径):
for f in os.listdir(dr):
s = f[0]; fsrc = path(dr, f)
检查项目是否为文件:
if os.path.isfile(fsrc):
定义第一个字符是否为alpha的目标文件夹:
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))
仅需两个命令和两个正则表达式即可进行代码组合但可读:
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:]]?*
如果没有文件与全局模式匹配,则不尝试移动原义文件名。find
与shell锁定相比,还允许更多的匹配条件。一种替代方法是设置nullglob
shell选项并关闭的标准输入流prename
。1个
在这两种情况下,-n
都应删除开关以实际移动文件,而不仅仅是显示如何移动文件。
附录:您可以使用以下方法再次删除空目录:
rmdir --ignore-fail-on-non-empty '#' {a..z}
1个 shopt -s nullglob; prename ... <&-
如果您不介意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
in mmv
定义的情况下再次运行以实际执行移动。
我没有想出一种使目录名变为大写(或使用大写字母移动文件)的好方法,尽管您以后可以使用rename
...
mkdir {a..z} \#; for i in {a..z}; do for f in "$i"*; do if [[ -f "$f" ]]; then echo mv -v -- "$f" "$i"; fi; done; done; for g in [![:alpha:]]*; do if [[ -f "$g" ]]; then echo mv -v -- "$g" \#; fi; done
或更可读:
mkdir {a..z} \#;
for i in {a..z}; do
for f in "$i"*; do
if [[ -f "$f" ]]; then
echo mv -v -- "$f" "$i";
fi
done
done
for g in [![:alpha:]]*; do
if [[ -f "$g" ]]; then
echo mv -v -- "$g" \#
fi
done
echo
经过测试以实际移动文件后删除
接着
rename -n 'y/[a-z]/[A-Z]/' *
-n
如果在测试后看起来不错,请删除并再次运行。
if [[ -d "${i^}" ]]
可变i
资本mkdir {A..Z}
。
包含字体的目录中的以下命令应该起作用,如果要从字体存储目录之外使用,请更改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' \;
使用tr
,然后mkdir
和将每个文件名映射到目录名称mv
:
find /src/dir -type f -print0 |
xargs -0 -I{} bash -c \
'dir=/dest/$(basename "{}" | cut -c1 | tr -C "a-zA-Z\n" "#" | tr "a-z "A-Z"); mkdir -p $dir; mv "{}" $dir'
tr
转换为大写。
xargs
只是为了bash
再次打电话?将输出传递find
到while循环中并read
逐条记录会更简单,更易读吗?
while
循环版本(bit.ly/2j2mhyb)可能更好。
{}
替代,如果你让xargs
附加参数,然后参考$1
shell脚本里面,例如:xargs -0 -n1 -- bash -c 'dir=/dest/$(basename "$1" | ...); ...; mv "$1" "$dir"' _
。(请注意决赛_
!)