Dem Dateinamen mit dem Befehl „Find“ voranstellen

Dem Dateinamen mit dem Befehl „Find“ voranstellen

Gibt es einen Wegmit nur dem Befehl findstellt man Dateinamen eine Zeichenfolge voran?

Damit dies:

201a.txt
201b.png
...

Wird dies:

foo_201a.txt
foo_201b.png
...

Das:

find . -name '201*' -execdir mv {} foo_{} \;

Funktioniert nicht, da der Teil den führenden Teil des Dateinamens {}enthält und daher versucht, in zu schreiben ../foo_./201*

Wenn dies nur mit „find“ nicht möglich ist, was ist die portabelste (sprich: nur Coreutils, keine Shell-Skripte, am einfachsten zu verstehende) Möglichkeit, Dateinamen einen String voranzustellen?

Antwort1

Nein. Aber der renameBefehl bietet eine einfache Lösung.

$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$

Antwort2

Wie wäre es mit

find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}

basenamewird von bereitgestellt coreutilsund da xargsvon bereitgestellt wird, findutilssollte es mindestens so portabel sein wie find -execdires selbst.


Alternativ können Sie nur die POSIX-Shell-Funktionen verwenden

find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;

Antwort3

Dies ist mit findallein nicht möglich, nicht einmal mit GNU find. GNU find kann Dateien drucken, bei denen das Befehlszeilenpräfix entfernt und stattdessen ein anderes Präfix eingefügt wurde, indem -printf foo_%panstelle von verwendet wird -print, aber für gibt es nichts Ähnliches -exec.

(Wenn Sie gerne gefährlich leben, können Sie verwenden find -printf 'mv foo_%p …' | sh. Dies funktioniert nur mit „zahmen“ Dateinamen und führt zu schrecklichen Abstürzen, wenn die Dateinamen Leerzeichen, Anführungszeichen oder andere Sonderzeichen enthalten. Tun Sie dies also nicht.)

Die Standardmethode hierfür (auf eine Weise, die auf jedem POSIX-System funktioniert und auch eine gängige Methode ist) besteht darin, für die Zeichenfolgenmanipulation eine Shell aufzurufen.

find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;

Ich verwende es nicht -execdir, weil es eine GNU-Erweiterung ist und Sie nach Portabilität gefragt haben. Beachten Sie, dass {}es als Argument an die Shell übergeben wird. Verwenden Sie es niemals {}innerhalb des Shell-Codes: nicht nur, weil es nicht portierbar ist, sondern vor allem, weil es dazu führen würde, dass der Dateiname als Shell-Code interpretiert würde, was fehlschlägt, wenn der Dateiname Sonderzeichen enthält.

Auf modernen POSIX-Systemen (alle aus dem letzten Jahrzehnt) können Sie diesen Befehl etwas beschleunigen, indem Sie die Shell-Aufrufe stapelweise ausführen.

find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +

Alternativ können Sie in ksh, bash oder zsh rekursives Globbing verwenden, anstatt aufzurufen find.

set -o globstar # ksh only
shopt -s globstar # bash only
for x in **/201*; do
  mv -- "$x" "${x%/*}/foo_${x##*/}"
done

Antwort4

Sie können stattdessen auch ein Sternchen ( *) verwenden, das den folgenden ./Teil entfernt:

find * -name '201*' -exec mv {} foo_{} \;  

verwandte Informationen