Es ergibt sich folgende Dateistruktur:
charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
this-file.waldo
another-file.waldo
Ich möchte alle Dateien im Stammordner umbenennen, in diesem Fall this-file.waldo
und another-file.waldo
. Wenn in einem Unterordner eine Datei mit demselben Basisnamen wie eine .waldo-Datei vorhanden ist, möchte ich die .waldo-Datei mit dem Namen des Unterordners umbenennen, der den Namensvetter enthält, wie folgt:
charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
charlie.waldo
foxtrot.waldo
Die Datei muss genau dann umbenannt werden, wenn ein Unterordner eine Datei mit demselben Basisnamen enthält und mit demselben Namen wie der Unterordner umbenannt werden muss.
Was wäre der effizienteste Weg, dies zu erreichen?
- Es wird immer eine .waldo-Datei vorhanden sein.
- Wenn es keine Datei mit dem gleichen Basisnamen gibt, sollte es diese einfach ignorieren und mit der nächsten fortfahren, bis eine Übereinstimmung gefunden wird.
- Bei den Dateinamen handelt es sich um normale Betriebssystem-Dateinamen, es können also &()[]# usw. vorhanden sein.
Antwort1
Das könnte etwa so aussehen:
for f (*.waldo(N)) (){ (($#)) && echo mv -- $f $1:h.waldo; } */$f:r.*(NY1)
(entfernen Sie den echo
(Trockenlauf), wenn Sie zufrieden sind).
Einige der weniger üblichen dort zu findenden zsh-Funktionen:
for f (values) action
: Kurzform der For-Schleife (ähnlich der Perl-Syntax)() { body; } args
: anonyme Funktion$var:r
:r
oot-Name (Teil ohne Erweiterung, wie in csh/vim...)$var:h
:h
ead (Verzeichnisname, wie in csh/vim)(N)
:N
ullglob Glob-Qualifizierer: Es wird also kein Fehler gemeldet, wenn keine Übereinstimmung vorliegt:(Y1)
: Stopp nach dem ersten Match-Glob-Qualifier.
Antwort2
Zunächst erhalten Sie eine Liste aller Dateien im aktuellen Verzeichnis
files=(*(.DoN))
dann machst du mit jedem von ihnen etwas:
for file in $files; do
# get the basename
bname="${file%%.*}"
# look for matches in subfolders
typeset -a matches_in_subfolders
matches_in_subfolders=*/${bname}*
# Check whether list of matches is longer than 0
if [ ${#matches_in_subfolders[@]} -gt 0 ] ; then
# do your magic renaming here
fi
done
Ich habe die Umbenennung hier nicht für Sie durchgeführt, da ich nicht sicher bin, wie ich mit mehreren Ergebnissen umgehen soll, aber
mv -- "${file}" "${matches_in_subfolders[0]}${file#*.}"
würde file
in den Namen des ersten Ordners umbenannt, der es enthält, und in die längste Erweiterung, die es hatte (wenn es nicht .waldo
, aber ist .foo.waldo
, nehme ich an, Sie möchten charlie.foo.waldo
, nicht nur charlie.waldo
).