如何根据文件名首字母将文件组织到 AZ 文件夹中

如何根据文件名首字母将文件组织到 AZ 文件夹中

我正在寻找一种方法(最好是终端)来按首字母组织超过 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))

如何使用

  1. 将脚本复制到一个空文件中,另存为move_files.py
  2. 使用目录作为参数运行它:

    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 通配符更多的匹配条件。另一种方法是设置nullglobshell 选项并关闭 的标准输入流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

再次运行(不使用echoinmmv的定义)来真正执行移动。

答案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' \;

相关内容