it-swarm.com.de

Wie kann ich Dateien basierend auf dem Anfangsbuchstaben ihres Dateinamens in A-Z-Ordnern organisieren?

Ich suche nach einer Möglichkeit (vorzugsweise ein Terminal), über 1000 Schriften nach ihrem Anfangsbuchstaben zu sortieren.

Erstellen Sie im Allgemeinen Verzeichnisse A-Z, # und verschieben Sie dann die Schriftdateien in diese Verzeichnisse, basierend auf dem Dateinamen des ersten Zeichens. Schriftarten, die mit Zahlen [0-9] oder anderen Sonderzeichen beginnen, werden in das Verzeichnis # verschoben.

15
Parto

Eine späte python Option:

#!/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))

Wie benutzt man

  1. Kopieren Sie das Skript in eine leere Datei und speichern Sie es als move_files.py
  2. Führen Sie es mit dem Verzeichnis als Argument aus:

    python3 /path/to/move_files.py /path/to/files
    

Das Skript erstellt nur dann das (Unter-) Verzeichnis (-ies) (in Großbuchstaben), wenn es tatsächlich benötigt wird

Erläuterung

Das Drehbuch:

  • listet die Dateien auf, erhält das erste Zeichen (definiert den Quellpfad):

    for f in os.listdir(dr):
        s = f[0]; fsrc = path(dr, f)
    
  • prüft, ob der Gegenstand eine Datei ist:

    if os.path.isfile(fsrc):
    
  • definiert den Zielordner, ob das erste Zeichen Alpha ist oder nicht:

    target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
    
  • prüft, ob der Ordner bereits existiert oder nicht, erstellt ihn, wenn nicht:

    if not os.path.exists(target):
        os.mkdir(target)
    
  • verschiebt das Objekt in den entsprechenden Ordner:

    shutil.move(fsrc, path(target, f))
    
13
Jacob Vlijm

Code-golfed und doch lesbar mit nur zwei Befehlen und zwei regulären Ausdrücken:

mkdir -p '#' {a..z}
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|' [[:alnum:]]?*

Wenn Sie eine große Anzahl von Dateien verschieben müssen, zu viele, um in die Liste der Prozessargumente zu passen (ja, es gibt ein Limit und es können nur einige Kilobyte sein), können Sie die Dateiliste mit einem anderen Befehl generieren und diese an weiterleiten prename, e. G.:

find -mindepth 1 -maxdepth 1 -name '[[:alnum:]]?*' -printf '%f\n' |
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|'

Dies hat den zusätzlichen Vorteil, dass nicht versucht wird, den Literal-Dateinamen [[:alnum:]]?* zu verschieben, wenn keine Dateien mit dem Glob-Muster übereinstimmen. find erlaubt auch viel mehr Übereinstimmungskriterien als Shell-Globbing. Eine Alternative besteht darin, die Shell-Option nullglob festzulegen und den Standardeingabestream von prename zu schließen.1

Entfernen Sie in beiden Fällen den Schalter -n, um die Dateien tatsächlich zu verschieben, und zeigen Sie nicht nur, wie sie verschoben würden.

Nachtrag: Sie können die leeren Verzeichnisse wieder entfernen mit:

rmdir --ignore-fail-on-non-empty '#' {a..z}

1 shopt -s nullglob; prename ... <&-

11
David Foerster

Ich habe keine gute Möglichkeit gefunden, die Verzeichnisnamen in Großbuchstaben zu schreiben (oder die Dateien in Großbuchstaben zu verschieben), obwohl Sie dies später mit rename ... tun könnten.

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

oder besser lesbar:

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

Entfernen Sie echo nach dem Test, um die Dateien tatsächlich zu verschieben

Und dann

rename -n 'y/[a-z]/[A-Z]/' *

entfernen Sie -n, wenn es nach dem Testen gut aussieht, und führen Sie es erneut aus.

8
Zanna

Wenn Sie nichts dagegen haben, zsh, eine Funktion und ein paar zmv -Befehle:

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'

Die Funktion mmv erstellt das Verzeichnis und verschiebt die Datei. zmv bietet dann Mustererkennung und -ersetzung. Verschieben Sie zuerst Dateinamen, die mit einem Alphabet beginnen, und dann alles andere:

$ 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

Führen Sie den Vorgang ohne echo in der Definition von mmv erneut aus, um die Verschiebung tatsächlich auszuführen.

8
muru

Die folgenden Befehle in dem Verzeichnis, das die Schriftarten enthält, sollten funktionieren. Wenn Sie sie außerhalb des Schriftarten-Speicherverzeichnisses verwenden möchten, ändern Sie for f in ./* in for f in /directory/containing/fonts/*. Dies ist eine sehr Shell-basierte Methode, also ziemlich langsam und auch nicht rekursiv. Dadurch werden nur Verzeichnisse erstellt, wenn Dateien vorhanden sind, die mit dem entsprechenden Zeichen beginnen.

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

Als Einzeiler wieder aus dem Font-Speicher-Verzeichnis heraus:

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

Eine Methode, die find mit einer ähnlichen Zeichenfolgenmanipulation verwendet und eine Bash-Parameter-Erweiterung verwendet, die rekursiv ist und etwas schneller als die reine Shell-Version sein sollte:

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

Oder besser lesbar:

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' \;
7
Arronical

Ordnen Sie jeden Dateinamen einem Verzeichnisnamen zu, indem Sie tr, dann mkdir und mv verwenden:

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'
5
xn.