Ich habe Dateien wie a_dbg.txt, b_dbg.txt ...
in einem Suse 10
System. Ich möchte ein Bash-Shell-Skript schreiben, das diese Dateien umbenennen soll, indem "_dbg" aus ihnen entfernt wird.
Google schlug mir vor, den rename
Befehl zu verwenden . Also habe ich den Befehl rename _dbg.txt .txt *dbg*
auf dem ausgeführtCURRENT_FOLDER
Mein aktueller CURRENT_FOLDER
enthält die folgenden Dateien.
CURRENT_FOLDER/a_dbg.txt
CURRENT_FOLDER/b_dbg.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt
Nach dem Ausführen des rename
Befehls
CURRENT_FOLDER/a.txt
CURRENT_FOLDER/b.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt
Es wird nicht rekursiv ausgeführt, wie dieser Befehl zum Umbenennen von Dateien in allen Unterverzeichnissen ausgeführt wird. Like XX
und YY
ich werden so viele Unterverzeichnisse haben, deren Name nicht vorhersehbar ist. Und ich CURRENT_FOLDER
werde auch einige andere Dateien haben.
Bareword "..." not allowed while "strict subs" in use at (eval 1) line 1.
Antworten:
Sie können verwenden
find
, um alle übereinstimmenden Dateien rekursiv zu finden:$ find . -iname "*dbg*" -exec rename _dbg.txt .txt '{}' \;
EDIT: was die
'{}'
und\;
sind?Das
-exec
Argument bewirkt, dass findrename
für jede gefundene übereinstimmende Datei ausgeführt wird.'{}'
wird durch den Pfadnamen der Datei ersetzt. Das letzte Token\;
dient nur zum Markieren des Endes des exec-Ausdrucks.Alles, was in der Manpage zu finden ist:
-exec utility [argument ...] ; True if the program named utility returns a zero value as its exit status. Optional arguments may be passed to the utility. The expression must be terminated by a semicolon (``;''). If you invoke find from a shell you may need to quote the semicolon if the shell would otherwise treat it as a control operator. If the string ``{}'' appears anywhere in the utility name or the argu- ments it is replaced by the pathname of the current file. Utility will be executed from the directory from which find was executed. Utility and arguments are not subject to the further expansion of shell patterns and constructs.
quelle
find . -type f "*dbg*" -exec rename "_dbg.txt" ".txt" * {} \;
Illegal octal digit '9' at (user-supplied code), at end of line
. Ich habe sowohl einfache Anführungszeichen als auch doppelte Anführungszeichen und keine Anführungszeichen für die Argumente von ausprobiertrename
. Ich versuche , speziell zu ersetzen0123-MISC
mit0123_AB_MISC
. Dies ist mein Befehlfind . -iname "*0123-MISC*" -exec rename 0123-MISC 0123_AB_MISC {} \;
Bareword "..." not allowed while "strict subs" in use at ...
, versuchen Sie:find . -iname "*BUILD*" -exec rename 's/_dbg.txt/.txt/' '{}' \;
find: rename: No such file or directory
Zum rekursiven Umbenennen verwende ich folgende Befehle:
find -iname \*.* | rename -v "s/ /-/g"
quelle
find -iname \*.* | rename -v -f "s/\.bak//g"
rename
versucht wird, den gesamten Pfad umzubenennen, und dies fehlschlägt, wenn ein übergeordnetes Verzeichnis geändert wird. Sie müssen stattdessen nur mit Basisnamen arbeiten, wie unter stackoverflow.com/questions/16541582/… gezeigt, und zuerst mit der Tiefe fortfahren-depth
.kleines Skript, das ich geschrieben habe, um alle Dateien mit der Erweiterung .txt in die Erweiterung .cpp unter / tmp und Unterverzeichnisse rekursiv zu ersetzen
#!/bin/bash for file in $(find /tmp -name '*.txt') do mv $file $(echo "$file" | sed -r 's|.txt|.cpp|g') done
quelle
for file in $(find ...)
. Siehe Warum Sie die Ausgabe von ls (1) nicht analysieren sollten .mit bash:
shopt -s globstar nullglob rename _dbg.txt .txt **/*dbg*
quelle
shopt -s globstar nullstar
. Für das Umbenennungs-Tool, das überbrew install rename
MacOS installiert ist , musste ich tunrename -s oldStuff newStuff **/*
find -execdir rename
https://stackoverflow.com/a/16541670/895245 funktioniert direkt nur für Suffixe, dies funktioniert jedoch für willkürliche Regex-Ersetzungen für Basisnamen:
PATH=/usr/bin find . -depth -execdir rename 's/_dbg.txt$/_.txt' '{}' \;
oder nur Dateien betreffen:
PATH=/usr/bin find . -type f -execdir rename 's/_dbg.txt$/_.txt' '{}' \;
-execdir
Zuerstcd
s in das Verzeichnis, bevor nur der Basisname ausgeführt wird.Getestet unter Ubuntu 20.04, finde 4.7.0, benenne 1.10 um.
Bequemer und sicherer Helfer dafür
find-rename-regex() ( set -eu find_and_replace="$1" PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \ find . -depth -execdir rename "${2:--n}" "s/${find_and_replace}" '{}' \; )
GitHub stromaufwärts .
Beispiel für die Verwendung von Leerzeichen '' durch Bindestriche '-'.
Trockenlauf, der zeigt, was in was umbenannt werden würde, ohne es tatsächlich zu tun:
find-rename-regex ' /-/g'
Ersetzen Sie:
find-rename-regex ' /-/g' -v
Befehlserklärung
Die fantastische
-execdir
Option führt im Gegensatz zumcd
Ausführen einesrename
Befehls vor der Ausführung des Befehls ein Verzeichnis durch-exec
.-depth
Stellen Sie sicher, dass die Umbenennung zuerst bei Kindern und dann bei Eltern erfolgt, um mögliche Probleme mit fehlenden Elternverzeichnissen zu vermeiden.-execdir
ist erforderlich, da das Umbenennen mit 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: Esfind
ist äußerst eigensinnig und weigert sich, irgendetwas damit zu tun,-execdir
wenn Sie relative Pfade in IhrerPATH
Umgebungsvariablen haben, z./node_modules/.bin
.Siehe auch: /ubuntu/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378
-execdir
ist eine GNU-Find- Erweiterung für POSIX .rename
ist Perl-basiert und kommt aus demrename
Paket.Benennen Sie die Lookahead-Problemumgehung um
Wenn Ihre Eingabepfade nicht von stammen
find
oder wenn Sie genug von der relativen Pfadstörung haben, können wir einige Perl-Lookaheads verwenden, um Verzeichnisse wie folgt sicher umzubenennen:git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
Ich habe kein passendes Analogon für gefunden
-execdir
mitxargs
: /superuser/893890/xargs-change-working-directory-to-file-path-before-executing/915686Dies
sort -r
ist erforderlich, um sicherzustellen, dass Dateien nach ihren jeweiligen Verzeichnissen kommen, da längere Pfade nach kürzeren mit demselben Präfix folgen.Getestet in Ubuntu 18.10.
quelle
Scipt oben kann in einer Zeile geschrieben werden:
find /tmp -name "*.txt" -exec bash -c 'mv $0 $(echo "$0" | sed -r \"s|.txt|.cpp|g\")' '{}' \;
quelle
Wenn Sie nur umbenennen möchten und nichts dagegen haben, ein externes Tool zu verwenden, können Sie rnm verwenden . Der Befehl wäre:
#on current folder rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' *
-dp -1
macht es rekursiv zu allen Unterverzeichnissen.-fo
impliziert den Nur-Datei-Modus.-ssf '_dbg'
sucht nach Dateien mit _dbg im Dateinamen.-rs '/_dbg//'
ersetzt _dbg durch eine leere Zeichenfolge.Sie können den obigen Befehl auch mit dem Pfad des CURRENT_FOLDER ausführen:
rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' /path/to/the/directory
quelle
Sie können dies unten verwenden.
rename --no-act 's/\.html$/\.php/' *.html */*.html
quelle
klassische Lösung:
for f in $(find . -name "*dbg*"); do mv $f $(echo $f | sed 's/_dbg//'); done
quelle
~/tmp$ mkdir a && cd a/ && touch 1_dbg.txt && cd ..
~/tmp$ for f in $(find . -name "*dbg*"); do mv $f $(echo $f | sed 's/_dbg//'); done
~/tmp$ cd a/ ~/tmp/a$ l total 8 drwxrwxr-x 2 repu1sion repu1sion 4096 Sep 17 21:17 . drwxrwxr-x 3 repu1sion repu1sion 4096 Sep 17 21:17 .. -rw-rw-r-- 1 repu1sion repu1sion 0 Sep 17 21:17 1.txt
for f in $(find ....)
: Tu das nicht! es bricht mit Dateinamen, die Leerzeichen oder Glob-Zeichen enthalten; außerdemfind
hat die-exec
Option , die sehr wahrscheinlich , stattdessen verwendet werden kann; oderfor f in *_dbg*; do
oder wenn Sie einen rekursiven Glob wollen,for f in **/*_dbg; do
mitshopt -s globstar
.shopt -s globstar nullglob; for f in **/*_dbg*; do mv -- "$f" "${f/_dbg}"; done
.