Ich habe nicht das Herz, alles noch einmal zu machen, aber ich habe dies als Antwort auf Commandline Find Sed Exec geschrieben . Dort wollte der Fragesteller wissen, wie ein ganzer Baum, möglicherweise mit Ausnahme eines oder zweier Verzeichnisse, verschoben und alle Dateien und Verzeichnisse mit der Zeichenfolge "OLD" in "NEW" umbenannt werden .
Neben der Beschreibung des wie mit mühsamer Ausführlichkeit unten kann dieses Verfahren auch eindeutig sein, dass es enthält eingebaute in debuggen. Grundsätzlich werden nur die Befehle kompiliert und in einer Variablen gespeichert, von denen es glaubt, dass sie ausgeführt werden sollen, um die angeforderte Arbeit auszuführen.
Außerdem werden Schleifen explizit so weit wie möglich vermieden . Abgesehen von der sed
rekursiven Suche nach mehr als einer Übereinstimmung des Musters gibt es meines Wissens keine andere Rekursion.
Und zuletzt ist dies vollständig null
abgegrenzt - es wird kein Zeichen in einem Dateinamen außer dem ausgelöst null
. Ich denke nicht, dass du das haben solltest.
Das ist übrigens WIRKLICH schnell. Aussehen:
% _mvnfind() { mv -n "${1}" "${2}" && cd "${2}"
> read -r SED <<SED
> :;s|${3}\(.*/[^/]*${5}\)|${4}\1|;t;:;s|\(${5}.*\)${3}|\1${4}|;t;s|^[0-9]*[\t]\(mv.*\)${5}|\1|p
> SED
> find . -name "*${3}*" -printf "%d\tmv %P ${5} %P\000" |
> sort -zg | sed -nz ${SED} | read -r ${6}
> echo <<EOF
> Prepared commands saved in variable: ${6}
> To view do: printf ${6} | tr "\000" "\n"
> To run do: sh <<EORUN
> $(printf ${6} | tr "\000" "\n")
> EORUN
> EOF
> }
% rm -rf "${UNNECESSARY:=/any/dirs/you/dont/want/moved}"
% time ( _mvnfind ${SRC=./test_tree} ${TGT=./mv_tree} \
> ${OLD=google} ${NEW=replacement_word} ${sed_sep=SsEeDd} \
> ${sh_io:=sh_io} ; printf %b\\000 "${sh_io}" | tr "\000" "\n" \
> | wc - ; echo ${sh_io} | tr "\000" "\n" | tail -n 2 )
<actual process time used:>
0.06s user 0.03s system 106% cpu 0.090 total
<output from wc:>
Lines Words Bytes
115 362 20691 -
<output from tail:>
mv .config/replacement_word-chrome-beta/Default/.../googlestars \
.config/replacement_word-chrome-beta/Default/.../replacement_wordstars
HINWEIS: Für die oben genannten function
Schritte sind wahrscheinlich GNU
Versionen von sed
und erforderlich find
, um die Aufrufe find printf
und sed -z -e
und ordnungsgemäß zu verarbeiten :;recursive regex test;t
. Wenn Ihnen diese nicht zur Verfügung stehen, kann die Funktionalität wahrscheinlich mit ein paar geringfügigen Anpassungen dupliziert werden.
Dies sollte alles tun, was Sie von Anfang bis Ende mit sehr wenig Aufwand wollten. Ich habe fork
mit sed
, aber ich war auch einige praktizierende sed
rekursive Verzweigung Techniken ist also, warum ich hier bin. Es ist so, als würde man in einer Friseurschule einen Rabatt-Haarschnitt bekommen, denke ich. Hier ist der Workflow:
rm -rf ${UNNECESSARY}
- Ich habe absichtlich jeden Funktionsaufruf ausgelassen, der Daten jeglicher Art löschen oder zerstören könnte. Sie erwähnen, dass
./app
dies unerwünscht sein könnte. Löschen Sie es oder verschieben Sie es vorher an eine andere Stelle, oder Sie können alternativ eine \( -path PATTERN -exec rm -rf \{\} \)
Routine einbauen, find
um dies programmgesteuert zu tun, aber das gehört Ihnen.
_mvnfind "${@}"
- Deklarieren Sie die Argumente und rufen Sie die Worker-Funktion auf.
${sh_io}
ist besonders wichtig, da es die Rückgabe von der Funktion speichert. ${sed_sep}
kommt in einer knappen Sekunde; Dies ist eine beliebige Zeichenfolge, die verwendet wird, um auf sed
die Rekursion in der Funktion zu verweisen . Wenn ${sed_sep}
auf einen Wert gesetzt ist, der möglicherweise in einem Ihrer Pfad- oder Dateinamen gefunden werden kann, auf die reagiert wird ... nun, lassen Sie es einfach nicht zu.
mv -n $1 $2
- Der ganze Baum wird von Anfang an bewegt. Es wird viel Kopfschmerzen sparen; glaube mir. Der Rest von dem, was Sie tun möchten - das Umbenennen - ist einfach eine Frage der Metadaten des Dateisystems. Wenn Sie dies beispielsweise von einem Laufwerk auf ein anderes oder über Dateisystemgrenzen hinweg verschieben, ist es besser, dies sofort mit einem Befehl zu tun. Es ist auch sicherer. Beachten Sie die
-noclobber
Option für mv
; Wie geschrieben, wird diese Funktion nicht dort platzieren, ${SRC_DIR}
wo ${TGT_DIR}
bereits eine vorhanden ist.
read -R SED <<HEREDOC
- Ich habe alle Befehle von sed hier gefunden, um Ärger zu vermeiden, und sie in eine Variable eingelesen, um sie unten an sed weiterzuleiten. Erklärung unten.
find . -name ${OLD} -printf
- Wir beginnen den
find
Prozess. Mit find
uns nur für etwas suchen , die Umbenennung braucht , weil wir bereits alle der tat Ort-zu-Ort - mv
Operationen mit der ersten Befehl der Funktion. Anstatt eine direkte Aktion mit beispielsweise find
einem exec
Aufruf auszuführen, verwenden wir sie stattdessen, um die Befehlszeile dynamisch mit aufzubauen -printf
.
%dir-depth :tab: 'mv '%path-to-${SRC}' '${sed_sep}'%path-again :null delimiter:'
- Nachdem
find
wir die benötigten Dateien gefunden haben, wird sie direkt erstellt und (der größte Teil ) des Befehls ausgedruckt, den wir zum Verarbeiten Ihrer Umbenennung benötigen. Das %dir-depth
am Anfang jeder Zeile angeheftete Element stellt sicher, dass nicht versucht wird, eine Datei oder ein Verzeichnis im Baum mit einem übergeordneten Objekt umzubenennen, das noch umbenannt werden muss. find
verwendet alle Arten von Optimierungstechniken, um Ihren Dateisystembaum zu durchsuchen, und es ist nicht sicher, ob die benötigten Daten in einer betriebssicheren Reihenfolge zurückgegeben werden. Deshalb werden wir als nächstes ...
sort -general-numerical -zero-delimited
- Wir sortieren die gesamte
find
Ausgabe danach, %directory-depth
sodass die Pfade, die in Bezug auf $ {SRC} am nächsten liegen, zuerst bearbeitet werden. Dies vermeidet mögliche Fehler beim mv
Einfügen von Dateien in nicht vorhandene Speicherorte und minimiert die Notwendigkeit einer rekursiven Schleife. ( Tatsächlich kann es schwierig sein, überhaupt eine Schleife zu finden. )
sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
- Ich denke, dies ist die einzige Schleife im gesamten Skript, und sie durchläuft nur die zweite Schleife, die
%Path
für jede Zeichenfolge gedruckt wird, falls sie mehr als einen $ {OLD} -Wert enthält, der möglicherweise ersetzt werden muss. Alle anderen Lösungen, die ich mir vorgestellt habe, beinhalteten einen zweiten sed
Prozess, und obwohl eine kurze Schleife möglicherweise nicht wünschenswert ist, schlägt sie sicherlich das Laichen und Verzweigen eines gesamten Prozesses.
- Im Grunde genommen
sed
wird hier nach $ {sed_sep} gesucht und dann, nachdem es gefunden wurde, es und alle Zeichen, auf die es trifft, gespeichert, bis es $ {OLD} findet, das es dann durch $ {NEW} ersetzt. Es kehrt dann zu $ {sed_sep} zurück und sucht erneut nach $ {OLD}, falls es mehr als einmal in der Zeichenfolge vorkommt. Wenn es nicht gefunden wird, druckt es die geänderte Zeichenfolge stdout
(an die es dann als nächstes wieder abfängt) und beendet die Schleife.
- Dadurch wird vermieden, dass die gesamte Zeichenfolge analysiert werden muss, und es wird sichergestellt, dass die erste Hälfte der
mv
Befehlszeichenfolge, die natürlich $ {OLD} enthalten muss, diese enthält und die zweite Hälfte so oft geändert wird, wie zum Löschen der Zeichenfolge erforderlich ist $ {OLD} Name aus mv
dem Zielpfad.
sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
- Die beiden
-exec
Anrufe hier erfolgen ohne Sekunde fork
. Wie wir gesehen haben, ändern wir im ersten Schritt den mv
Befehl, der vom Funktionsbefehl find
's bereitgestellt wird , -printf
nach Bedarf, um alle Verweise von $ {OLD} auf $ {NEW} ordnungsgemäß zu ändern. Dazu mussten wir jedoch einige verwenden beliebige Referenzpunkte, die nicht in die endgültige Ausgabe aufgenommen werden sollten. Sobald sed
alles erledigt ist, weisen wir es an, seine Referenzpunkte aus dem Haltepuffer zu löschen, bevor es weitergegeben wird.
Und jetzt sind wir wieder da
read
erhält einen Befehl, der folgendermaßen aussieht:
% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000
Es wird read
es ${msg}
als ${sh_io}
was nach Belieben außerhalb der Funktion untersucht werden kann.
Cool.
-Mike