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 rename
Befehl 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_{}
basename
wird von bereitgestellt coreutils
und da xargs
von bereitgestellt wird, findutils
sollte es mindestens so portabel sein wie find -execdir
es 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 find
allein 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_%p
anstelle 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_{} \;