zsh: Datei umbenennen, wenn Datei im Unterordner denselben Namen hat

zsh: Datei umbenennen, wenn Datei im Unterordner denselben Namen hat

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.waldound 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: root-Name (Teil ohne Erweiterung, wie in csh/vim...)
  • $var:h: head (Verzeichnisname, wie in csh/vim)
  • (N): Nullglob 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 filein 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).

verwandte Informationen