Je recherche un moyen (de préférence terminal) d’organiser plus de 1000 polices par leur première lettre.
Fondamentalement, créez les répertoires A-Z, #
, puis déplacez les fichiers de police dans ces répertoires en fonction du premier caractère de leur nom de fichier. Les polices commençant par les chiffres [0-9] ou d’autres caractères spéciaux doivent être déplacées vers le répertoire #
.
Une option python tardive:
#!/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
Exécutez-le avec le répertoire comme argument:
python3 /path/to/move_files.py /path/to/files
Le script créera uniquement le (sous) répertoire (-ies) (majuscule) s'il est réellement nécessaire
Le scénario:
liste les fichiers, obtient le premier caractère (définit le chemin source):
for f in os.listdir(dr):
s = f[0]; fsrc = path(dr, f)
vérifie si l'élément est un fichier:
if os.path.isfile(fsrc):
définit le dossier ciblé si le premier caractère est alpha ou non:
target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
vérifie si le dossier existe déjà ou non, le crée sinon:
if not os.path.exists(target):
os.mkdir(target)
déplace l'élément dans le dossier correspondant:
shutil.move(fsrc, path(target, f))
Code-golfé mais lisible avec seulement deux commandes et deux expressions régulières:
mkdir -p '#' {a..z}
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|' [[:alnum:]]?*
Si vous avez une quantité énorme de fichiers à déplacer, trop pour pouvoir être insérés dans la liste des arguments du processus (oui, il y a une limite et cela peut ne représenter que quelques kilo-octets), vous pouvez générer la liste de fichiers avec une commande différente et la diriger vers prename
, e. g.:
find -mindepth 1 -maxdepth 1 -name '[[:alnum:]]?*' -printf '%f\n' |
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|'
Cela présente l’avantage supplémentaire de ne pas essayer de déplacer le nom de fichier littéral [[:alnum:]]?*
si aucun fichier ne correspond au modèle glob. find
autorise également beaucoup plus de critères de correspondance que l'écriture de shell. Une autre solution consiste à définir l'option Shell à nullglob
et à fermer le flux d'entrée standard de prename
.1
Dans les deux cas, supprimez le commutateur -n
pour déplacer réellement les fichiers et ne montrez pas simplement comment ils seraient déplacés.
Addendum: Vous pouvez à nouveau supprimer les répertoires vides avec:
rmdir --ignore-fail-on-non-empty '#' {a..z}
1 shopt -s nullglob; prename ... <&-
Je n'ai pas trouvé de solution intéressante pour mettre les noms de répertoire en majuscule (ou déplacer les fichiers avec des lettres en majuscule), bien que vous puissiez le faire ultérieurement avec 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
ou plus lisiblement:
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
Supprimer echo
après le test pour réellement déplacer les fichiers
Et alors
rename -n 'y/[a-z]/[A-Z]/' *
supprimez -n
s'il semble bon après le test et exécutez-le à nouveau.
Si zsh, une fonction et quelques commandes zmv
vous intéressent:
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'
La fonction mmv
crée le répertoire et déplace le fichier. zmv
fournit ensuite une correspondance de modèle et une substitution. Tout d’abord, déplacez les noms de fichiers en commençant par un alphabet, puis tout le reste:
$ 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
Réexécutez l'opération sans la définition de echo
dans mmv
name __ afin d'effectuer le déplacement.
Les commandes suivantes du répertoire contenant les polices doivent fonctionner. Si vous souhaitez utiliser de l’extérieur du répertoire de stockage des polices, remplacez for f in ./*
par for f in /directory/containing/fonts/*
. C'est une méthode très basée sur Shell, donc assez lente et non récursive. Cela ne créera que des répertoires, s'il existe des fichiers qui commencent par le caractère correspondant.
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
En une ligne, toujours à partir du répertoire de stockage des polices:
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
Une méthode utilisant find, avec une manipulation de chaîne similaire, utilisant le développement de paramètres bash, qui sera récursive et devrait être un peu plus rapide que la version pure 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' \;
Ou plus lisiblement:
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' \;
Mappez chaque nom de fichier sur un nom de répertoire en utilisant tr
, puis mkdir
et 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'