Wie verschiebe ich jede Datei in einem Ordner in ein gleichnamiges Unterverzeichnis?

Wie verschiebe ich jede Datei in einem Ordner in ein gleichnamiges Unterverzeichnis?

Angenommen, ich habe eine Reihe von Dateien in einem Verzeichnis

filename-1.ext1
filename-1.ext2
filename-1.ext3
filename-2.ext1
filename-2.ext2
filename-2.ext3
filename-3.ext1
filename-3.ext2
filename-3.ext3

Ich möchte dann Unterverzeichnisse im selben Verzeichnis mit demselben Namen wie die Dateien erstellen (Dateiname, aber keine Erweiterung) und sie wie folgt verschieben

filename-1
├──filename-1.ext1
├──filename-1.ext2
└──filename-1.ext3
filename-2
├──filename-2.ext1
├──filename-2.ext2
└──filename-2.ext3
filename-3
├──filename-3.ext1
├──filename-3.ext2
└──filename-3.ext3

Was wäre der effizienteste Weg, dies zu erreichen?

Bearbeiten: ext1, ext2, ext3 dienen nur dazu, drei verschiedene Dateinamen anzuzeigen, wie .foo, .bar, .top, .coffee usw. Nicht, dass die Dateinamen ähnlich wären.

Antwort1

Da Sie verwenden zsh, könnte dies folgendermaßen erfolgen:

for name (*.ext<->(.)) mkdir -p -- $name:r && mv -- $name $name:r 

oder mit der bekannteren Langform der forSchleife,

for name in *.ext<->(.); do
    mkdir -p -- $name:r &&
    mv -- $name $name:r
done

Dies durchläuft alle regulären Dateien, die dem Muster entsprechen, *.ext<->wobei <->eine beliebige Zahl übereinstimmen muss. Es ist der Glob-Qualifizierer (.), der die Übereinstimmung nur mit regulären Dateien erzwingt. Ändern Sie das gesamte Muster in , *.*(.)wenn Sie den Dateinamen einer beliebigen regulären Datei abgleichen möchten, der einen Punkt enthält. Wir benötigen den Punkt, da Sie eine Dateinamenerweiterung später entfernen möchten. Um ein strengeres statt eines lockereren Musters zu verwenden, verwenden Sie etwas wie filename-<->.ext<->(.). Dieses Muster erfordert, dass Sie wissen, dass Sie Namen abgleichen möchten, die mit der Zeichenfolge beginnen filename-.

Die $name:rErweiterung ergibt den gleichen Wert wie $name, jedoch ohne die Erweiterung (d. h. nur die „Wurzel“ des Wertes).

Wir verwenden es, --um beiden das Ende von Optionen zu signalisieren mkdirund mvum zu verhindern, dass Namen, die mit einem Bindestrich beginnen, mit Optionen verwechselt werden.

Antwort2

Mit zmv:

autoload -Uz zmv # best in ~/.zshrc
mkmv() { mkdir -p -- $2:h && mv -- "$@"; }

zmv -P mkmv -n '(*).ext<->(#q.)' '$1/$f'

(entfernen -n, wenn zufrieden).

Auf diese Weise profitieren Sie von zmvden Plausibilitätsprüfungen von .

Antwort3

Verwenden Sie diese forSchleife, die sowohl mit Bash- als auch mit Zsh-Shells kompatibel ist:

for file in *.*; do
  [ -f "$file" ] &&
    mkdir -p -- "${file%.*}" &&
    mv -- "$file" "${file%.*}/"
done
  • -pOption mkdirstellt sicher, dass die Datei vorhanden ist. Der Fehler wird nicht ausgelöst.
  • %.*entfernt die Erweiterung aus den Dateinamen.

Antwort4

Mit GNU Parallel (ein Tool, dessen Leistungsfähigkeit mir gerade erst bewusst wird):

ls | parallel 'mkdir -p {.}; mv -i {} {.}'

Da dies in keiner Weise an die CPU gebunden ist, wird es vermutlich parallelkeine Geschwindigkeitsvorteile bringen, ist aber immer noch kürzer als viele der anderen angebotenen Lösungen.

Und dies hängt nicht vom Muster der Dateinamen ab.

verwandte Informationen