Antworten:
Ein portabler Weg (der auf jedem POSIX-kompatiblen System funktioniert):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
In bash4 können Sie globstar verwenden, um rekursive Globs zu erhalten (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
Der (Perl) rename
-Befehl in Ubuntu kann Dateien mithilfe der Perl-Syntax für reguläre Ausdrücke umbenennen, die Sie mit globstar kombinieren können, oder find
:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
Siehe auch http://mywiki.wooledge.org/BashFAQ/030
"${1%.abc}"
erweitert sich am Ende auf den Wert von $1
except without .abc
. Weitere Informationen zu Shell-String-Manipulationen finden Sie in FAQ 100 .
${1%.abc}...
sh -c
dem ersten Argument $ 0 zugewiesen wird und alle verbleibenden Argumente den Positionsparametern zugewiesen werden . Das _
ist also ein Scheinargument, und '{}' ist das erste Positionsargument für sh -c
.
Dies erledigt die erforderliche Aufgabe, wenn sich alle Dateien in demselben Ordner befinden
rename 's/.abc$/.edefg/' *.abc
So benennen Sie die Dateien rekursiv um:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abc
in einer modernen Version von Bash.
s
am Anfang und welche anderen Optionen kann ich dort verwenden. Vielen Dank !
Ein Problem bei rekursiven Umbenennungen besteht darin, dass unabhängig von der Methode, mit der Sie die Dateien suchen, der gesamte Pfad rename
und nicht nur der Dateiname übergeben wird. Das macht es schwierig, komplexe Umbenennungen in verschachtelten Ordnern vorzunehmen.
Ich benutze find
die -execdir
Aktion, um dieses Problem zu lösen. Wenn Sie -execdir
anstelle von verwenden -exec
, wird der angegebene Befehl aus dem Unterverzeichnis ausgeführt, das die übereinstimmende Datei enthält. Anstatt den gesamten Pfad dahin zu führen rename
, geht er nur vorbei ./filename
. Das macht es viel einfacher, den regulären Ausdruck zu schreiben.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
Im Detail:
-type f
bedeutet nur nach Dateien suchen, nicht nach Verzeichnissen-name '*.abc'
bedeutet, dass nur Dateinamen gefunden werden, die auf .abc enden'{}'
ist der Platzhalter, der die Stelle markiert, an der -execdir
der gefundene Pfad eingefügt wird. Die einfachen Anführungszeichen sind erforderlich, damit Dateinamen mit Leerzeichen und Shell-Zeichen behandelt werden können.-type
und -name
sind das Bash-Zeilenfortsetzungszeichen. Ich verwende sie, um dieses Beispiel besser lesbar zu machen, aber sie werden nicht benötigt, wenn Sie Ihren Befehl in eine einzige Zeile schreiben.-execdir
Zeile ist jedoch erforderlich. Es ist dazu da, das Semikolon zu verlassen, das den von ausgeführten Befehl beendet -execdir
. Spaß!Erklärung des regulären Ausdrucks:
s/
Beginn der Regex\.\/
stimmen Sie mit der führenden ./ überein, die -execdir eingibt. Verwenden Sie \, um die. und / oder Metazeichen (Hinweis: Dieser Teil variiert je nach Ihrer Version von find
. Siehe Kommentar von Benutzer @apollo)(.+)
stimmen mit dem Dateinamen überein. Die Klammern erfassen die Übereinstimmung für die spätere Verwendung\.abc
Entkomme dem Punkt und passe das ABC an$
Verankern Sie die Übereinstimmung am Ende der Zeichenfolge
/
markiert das Ende des "Match" -Teils des regulären Ausdrucks und den Beginn des "Ersetzen" -Teils
version1_
Fügen Sie diesen Text jedem Dateinamen hinzu
$1
verweist auf den vorhandenen Dateinamen, da dieser in Klammern angegeben ist. Wenn Sie im Teil "Übereinstimmung" mehrere Sätze von Klammern verwenden, können Sie hier mit $ 2, $ 3 usw. darauf verweisen..abc
Der neue Dateiname endet mit .abc. Das Punkt-Metazeichen muss hier im Abschnitt "Ersetzen" nicht entfernt werden/
Ende der RegexVor
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
Nach
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Hinweis: rename
Die Option -n ist nützlich. Es führt einen Trockenlauf durch und zeigt Ihnen, welche Namen es ändern wird, nimmt jedoch keine Änderungen vor.
--execdir
nicht in der Führung vorbeigekommen , ./
so dass der \.\/
Teil in der Regex weggelassen werden kann. Mai das ist, weil ich auf OSX nicht Ubuntu
Ein weiterer portabler Weg:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
Lesen Sie auch den Eintrag, warum Sie nicht analysieren sollten ls
.
Bearbeiten: Wenn Sie den Basisnamen verwenden müssen, lautet Ihre Syntax:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
Dies ist, was ich getan und ziemlich genau so gearbeitet habe, wie ich es wollte. Ich habe den mv
Befehl verwendet. Ich hatte mehrere .3gp
Dateien und wollte sie alle in umbenennen.mp4
Hier ist ein kurzer Oneliner dafür:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
Der durchsucht einfach das aktuelle Verzeichnis, nimmt alle .3gp-Dateien auf und benennt sie dann (mit dem MV) in um ren-name_of_file.mp4
file.3gp
zu file.3gp.mp4
, was vielleicht nicht , was die meisten Leute wollen.
.3gp
oder .mp4
hier waren nur zu Illustrationszwecken.
basename "$i" .mp4
, um die vorherige Erweiterung anstelle von "ren- $ i.mp4" zu entfernen.
Ich würde den Befehl mmv aus dem gleichnamigen Paket verwenden :
mmv ';*.abc' '#1#2.edefg'
Die ;
entspricht null oder mehr */
und entspricht #1
in der Ersetzung. Das *
entspricht #2
. Die nicht-rekursive Version wäre
mmv '*.abc' '#1.edefg'
Benennen Sie Dateien und Verzeichnisse mit find -execdir | rename
Wenn Sie Dateien und Verzeichnisse nicht einfach mit einem Suffix umbenennen, ist dies ein gutes Muster:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find . -depth -execdir rename 's/findme/replaceme/' '{}' \;
Anders -execdir
als cd
bei der Option " awesome " wird vor dem Ausführen des rename
Befehls ein Eintrag in das Verzeichnis erstellt -exec
.
-depth
Stellen Sie sicher, dass die Umbenennung zuerst bei Kindern und dann bei Eltern erfolgt, um potenzielle Probleme mit fehlenden Elternverzeichnissen zu vermeiden.
-execdir
ist erforderlich, weil das Umbenennen bei Eingabepfaden ohne Basisnamen nicht gut funktioniert, z. B. schlägt Folgendes fehl:
rename 's/findme/replaceme/g' acc/acc
Das PATH
Hacken ist erforderlich, da -execdir
es einen sehr ärgerlichen Nachteil hat: Es find
ist äußerst kritisch und weigert sich, irgendetwas damit zu tun, -execdir
wenn Sie relative Pfade in Ihrer PATH
Umgebungsvariablen haben, z ./node_modules/.bin
.
find: Der relative Pfad './node_modules/.bin' ist in der Umgebungsvariablen PATH enthalten, die in Kombination mit der Aktion -execdir von find unsicher ist. Bitte entfernen Sie diesen Eintrag aus $ PATH
Siehe auch: Warum ist die Verwendung der Aktion '-execdir' für Verzeichnisse im PATH unsicher?
-execdir
ist eine GNU find Erweiterung zu POSIX . rename
ist Perl-basiert und stammt aus dem rename
Paket. Getestet in Ubuntu 18.10.
Benennen Sie die Lookahead-Problemumgehung um
Wenn Ihre Eingabepfade nicht von stammen find
oder wenn Sie genug von der relativen Pfadbelästigung haben, können wir einige Perl-Lookaheads verwenden, um Verzeichnisse sicher umzubenennen, wie in:
git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
Ich habe nicht eine bequeme analog gefunden -execdir
mit xargs
: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
Das sort -r
ist erforderlich, um sicherzustellen, dass Dateien nach ihren jeweiligen Verzeichnissen kommen, da längere Pfade nach kürzeren mit demselben Präfix kommen.