Tipp: Führen Sie die folgenden Schritte nicht in einem SVN-Checkout-Baum aus. Dadurch werden magische .svn-Ordnerdateien überschrieben.
J. Polfer
7
Oh mein Gott, genau das habe ich gerade getan. Aber es hat funktioniert und scheint keinen Schaden angerichtet zu haben. Was ist das Schlimmste, was passieren könnte?
J. Katzwinkel
5
@ J.Katzwinkel: Zumindest kann es Prüfsummen beschädigen, die Ihr Repository beschädigen können.
Ninjagecko
3
Schneller Tipp für alle Benutzer von sed: Es werden Ihren Dateien nachfolgende Zeilenumbrüche hinzugefügt. Wenn Sie sie nicht wollen, führen Sie zuerst einen Find-Replace durch, der zu nichts passt, und übertragen Sie ihn auf Git. Dann mach den echten. Dann interaktiv neu starten und den ersten löschen.
Funroll
5
Sie können ein Verzeichnis, wie git, aus den Ergebnissen ausschließen , indem Sie -path ./.git -prune -oin find . -path ./.git -prune -o -type f -name '*matchThisText*' -print0vor dem xargs kochend
devinbost
Antworten:
849
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
-print0weist findan, jedes der Ergebnisse durch ein Nullzeichen anstatt durch eine neue Zeile zu drucken. In dem unwahrscheinlichen Fall, dass Ihr Verzeichnis Dateien mit Zeilenumbrüchen in den Namen enthält, können Sie dennoch xargsdie richtigen Dateinamen bearbeiten.
\( -type d -name .git -prune \)ist ein Ausdruck, der alle genannten Verzeichnisse vollständig überspringt .git. Sie können es leicht erweitern, wenn Sie SVN verwenden oder andere Ordner haben, die Sie beibehalten möchten - stimmen Sie einfach mit mehr Namen überein. Es ist ungefähr gleichwertig -not -path .git, aber effizienter, da es nicht jede Datei im Verzeichnis überprüft, sondern vollständig überspringt. Das -oNachher ist erforderlich, weil es -prunetatsächlich funktioniert.
Unter OSX können sed: 1: "...": invalid command code .Probleme auftreten. Es scheint, dass die Option -i eine Erweiterung erwartet und den 's/../...'Befehl parses ausgibt . Lösung: Übergeben Sie die Erweiterung '' an die Option -i wie sed -i '' 's/....
Robert Lujo
6
Hinweis: Wenn Sie dies über ein Verzeichnis verwenden und sich fragen, warum svn stkeine Änderungen angezeigt werden, liegt dies daran, dass Sie auch Dateien in den .svn-Verzeichnissen geändert haben! Verwenden Sie find . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'stattdessen.
ACK_stoverflow
57
Seien Sie auch vorsichtig, wenn Sie in einem Git-Repo sind. Ich dachte, ich wäre schlau, indem ich dies an einem klaren Zweig testete, damit ich zurückkehren konnte, wenn es etwas Schlimmes tat, aber stattdessen meinen Git-Index beschädigte.
Ciryon
13
Verwenden Sie diese Option grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g', um zu vermeiden, dass nicht verwandte Dateien bearbeitet werden (sed kann die Dateicodierung ändern).
Caiguanhao
6
"aber stattdessen meinen Git-Index beschädigt." Mach dir keine Sorgen, du kannst einfach find .git ... | ... 'sed -i s/(the opposite from before)/g'deinen Git-Index reparieren
Massey101
259
Hinweis : Führen Sie diesen Befehl nicht in einem Ordner aus, der ein Git-Repo enthält. Änderungen an .git können Ihren Git-Index beschädigen.
find /home/www/-type f -exec \
sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'{}+
Im Vergleich zu anderen Antworten hier ist dies einfacher als die meisten anderen und verwendet sed anstelle von perl, was in der ursprünglichen Frage gefordert wurde.
Beachten Sie, dass Sie bei Verwendung von BSD sed (einschließlich unter Mac OS X) der -iOption von sed ein explizites leeres String-Argument geben müssen . dh: sed -i '' 's/original/replacement/g'
Nathan Craike
2
@ JohnZwinck Mein Fehler, das + verpasst. Seltsamerweise läuft Nikitas Lösung für mich schneller.
Sam
6
@AoeAoe: Dadurch +wird die Anzahl der erzeugten sedProzesse erheblich reduziert . Es ist effizienter.
John Zwinck
4
Wie kann ich dies sicher in einem Ordner mit einem Git-Repo tun?
Hatschepsut
20
Die Ausführung in einem Ordner mit einem Git-Repo ist sicher, wenn Sie das Repo von Ihren Suchergebnissen ausschließen : find . -not -path '*/\.git*' -type f ....
Dale Anderson
210
Der einfachste Weg für mich ist
grep -rl oldtext .| xargs sed -i 's/oldtext/newtext/g'
@Anatoly: nur eine Frage: Wie kann ich Binärdateien (ausführbare Dateien) ausschließen ?
user2284570
3
@ user2284570 Verwenden Sie die Flags -Ioder --binary-file=without-matchgrep.
Zéychin
34
Dies funktioniert besonders gut, wenn Sie Verzeichnisse wie mit ausschließen müssen .svn. Zum Beispiel:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
Phyatt
11
brew install gnu-sedund gsedunter OSX verwenden, um eine Welt voller Schmerzen zu vermeiden.
P i
1
Jungs, bitte aufgepasst, wenn euer Projekt git-versioniert ist, benutze stattdessen Folgendes : git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'. Es ist überhaupt nicht schön, dein .gitDir
Paolo
61
Alle Tricks sind fast gleich, aber ich mag diesen:
find <mydir>-type f -exec sed -i 's/<string1>/<string2>/g'{}+
find <mydir>: im Verzeichnis nachschlagen.
-type f::
Die Datei ist vom Typ: reguläre Datei
-exec command {} +::
Diese Variante der Aktion -exec führt den angegebenen Befehl für die ausgewählten Dateien aus. Die Befehlszeile wird jedoch erstellt, indem jeder ausgewählte Dateiname am Ende angehängt wird. Die Gesamtzahl der Aufrufe des Befehls ist viel geringer als die Anzahl der übereinstimmenden Dateien. Die Befehlszeile wird ähnlich wie xargs seine Befehlszeilen erstellt. Innerhalb des Befehls ist nur eine Instanz von "{}" zulässig. Der Befehl wird im Startverzeichnis ausgeführt.
@ I159 Ist diese Antwort nicht identisch mit der von John Zwinck ?
Setzen Sie Monica bitte
1
@ user2284570 Das Konzept einer "Binärdatei" ist nicht ganz genau definiert. Sie können den fileBefehl verwenden, um zu versuchen, den Dateityp jeder Datei zu bestimmen, aber die zufälligen Abweichungen in der Ausgabe können etwas verwirrend sein. Die -I(aka --mime) Option hilft etwas, oder --mime-typewenn Sie das haben. Wie genau man diesen ordentlichen Einzeiler umgestaltet, um dies zu tun, ist für dieses winzige Kommentarfeld leider nicht möglich. Vielleicht eine separate Frage stellen, wenn Sie Hilfe benötigen? (Vielleicht fügen Sie dann hier einen Kommentar mit einem Link hinzu.)
Tripleee
1
die sauberste Antwort! danke Kumpel
Jukerok
39
cd /home/www && find .-type f -print0 |
xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
Ich bin neugierig, gibt es einen Grund zu verwenden -print0und xargsanstelle von -execoder -execdir?
Philipp
4
Es gibt: von "man find": Der angegebene Befehl wird einmal für jede übereinstimmende Datei ausgeführt. Das heißt, wenn sich 2000 Dateien in / home / www befinden, führt 'find ... -exec ...' zu 2000 Perl-Aufrufen. während 'find ... | xargs ... 'ruft Perl nur ein- oder zweimal auf (unter der Annahme von ARG_MAX von ca. 32 KB und einer durchschnittlichen Dateinamenlänge von 20).
Angestellt Russisch
2
@Employed Russian: Deshalb würden Sie verwenden find -exec command {} +- es vermeidet übermäßige Aufrufe des Befehls wie xargs, jedoch ohne den separaten Prozess.
John Zwinck
2
Auf welcher Plattform? Die xargs-Lösung ist portabel, die "magischen" Aufrufe von "find ... -exec", die nicht für jede gefundene Datei einen Unterprozess aufrufen, nicht.
Angestellt Russisch
4
@EmployedRussian, find -exec ... {} +ist seit 2006 POSIX-spezifiziert.
HINWEIS : Wenn zu viele Dateien verarbeitet werden müssen, erhalten Sie Argument list too long. Die oben beschriebene Problemumgehung - Verwendung find -execoder xargsLösung.
Das workaroundsollte die bevorzugte Syntax in allen Fällen.
Setzen Sie Monica bitte
1
Das Problem bei der Befehlssubstitution $(find...)besteht darin, dass die Shell keine Möglichkeit hat, Dateinamen mit Leerzeichen oder anderen Shell-Metazeichen zu verarbeiten. Wenn Sie wissen, dass dies kein Problem ist, ist dieser Ansatz in Ordnung. Wir haben jedoch zu viele Fragen, bei denen die Leute nicht über dieses Problem gewarnt wurden oder die Warnung nicht verstanden haben.
Gute Idee, wenn Sie in einem Git-Repo arbeiten, da Sie nicht riskieren, .git / content zu überschreiben (wie in den Kommentaren zu einer anderen Antwort angegeben).
Mahemoff
1
Danke, ich benutze es als Bash-Funktion. refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }Verwendung, zum Beispiel um 'Wort' durch 'Schwert' zu ersetzen: refactor word swordÜberprüfen Sie dann, was es getan hat git diff.
Paul Rougieux
16
Um Dateien zu rekursiv zu reduzieren sed, können Sie grepfür Ihre Zeichenfolgeninstanz Folgendes tun:
grep -rl <oldstring>/path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Wenn Sie ausführen, werden man grepSie feststellen, dass Sie auch ein --exlude-dir="*.git"Flag definieren können, wenn Sie das Durchsuchen von Git-Verzeichnissen unterlassen möchten, um Git-Index-Probleme zu vermeiden, wie andere höflich hervorgehoben haben.
Sie führen zu:
grep -rl --exclude-dir="*.git"<oldstring>/path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Klügere verwenden git-grep‚s - -zOption zusammen mit xargs -0.
gniourf_gniourf
git grepmacht natürlich nur in einem gitrepo Sinn . Der allgemeine Ersatz wäre grep -r.
Tripleee
@gniourf_gniourf Kannst du das erklären?
Petr Peller
2
@PetrPeller: with -z, git-greptrennt die Ausgabefelder durch Null-Bytes anstelle von Zeilenumbrüchen. und mit -0, xargsliest die Eingabe von Null - Bytes getrennt, statt Leerzeichen (und nicht tun seltsame Dinge mit Anführungszeichen). Wenn Sie also nicht möchten, dass der Befehl unterbrochen wird, wenn die Dateinamen Leerzeichen, Anführungszeichen oder andere lustige Zeichen enthalten, lautet der Befehl : git grep -z -l 'original_text' | xargs -0 sed ....
gniourf_gniourf
10
find /home/www/-type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'{}+
find /home/www/ -type f listet alle Dateien in / home / www / (und seinen Unterverzeichnissen) auf. Das Flag "-exec" weist find an, den folgenden Befehl für jede gefundene Datei auszuführen.
ist der Befehl, der für die Dateien ausgeführt wird (viele gleichzeitig). Das {}wird durch Dateinamen ersetzt. Am +Ende des Befehls wird angegeben find, dass ein Befehl für viele Dateinamen erstellt werden soll.
In der findManpage heißt es: "Die Befehlszeile ist ähnlich aufgebaut wie xargs seine Befehlszeilen."
So ist es möglich, Ihr Ziel zu erreichen (und Dateinamen mit Leerzeichen zu behandeln), ohne xargs -0oder zu verwenden -print0.
Ack-grep ist sehr effizient beim Auffinden relevanter Dateien. Dieser Befehl ersetzte ~ 145 000 Dateien durch einen Kinderspiel, während andere so lange dauerten, dass ich nicht warten konnte, bis sie fertig waren.
Schön, aber grep -ril 'subdomainA' *bei weitem nicht so schnell wie grep -Hr 'subdomainA' * | cut -d: -f1.
Trusktr
@Henno: nur eine Frage: Wie kann ich Binärdateien (ausführbare Dateien) ausschließen ?
user2284570
ack-grep erledigt das automatisch für Sie.
Henno
@Henno: Enthält es Shell-Skripte?
user2284570
Ja. Hier ist eine vollständige Liste der unterstützten Dateitypen
Henno
6
Eine einfache Methode, wenn Sie Verzeichnisse ( --exclude-dir=.svn) ausschließen müssen und möglicherweise auch Dateinamen mit Leerzeichen haben (mit 0Byte mit grep -Zundxargs -0
grep -rlZ oldtext .--exclude-dir=.svn | xargs -0 sed -i 's/oldtext/newtext/g'
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
Ich denke, die meisten Leute wissen nicht, dass sie etwas in eine "while read file" leiten können, und es vermeidet diese fiesen -print0-Argumente, während Leerzeichen in Dateinamen beibehalten werden.
Wenn Sie ein echovor dem sed hinzufügen, können Sie sehen, welche Dateien sich ändern, bevor Sie es tatsächlich tun.
Der Grund -print0dafür ist, dass Fälle behandelt werden, die while readeinfach nicht behandelt werden können. Ein Zeilenumbruch ist ein gültiges Zeichen in einem Unix-Dateinamen. Damit Ihr Code vollständig robust ist, muss er auch mit solchen Dateinamen umgehen. (Außerdem möchten Sie read -rein lästiges POSIX-Legacy-Verhalten in vermeiden read.)
Tripleee
Außerdem ist das sedein No-Op, wenn es keine Übereinstimmungen gibt, so dass das grepnicht wirklich notwendig ist; Dies ist jedoch eine nützliche Optimierung, um zu vermeiden, dass Dateien neu geschrieben werden, die keine Übereinstimmungen enthalten, wenn Sie viele davon haben oder Datumsstempel für Dateien nicht unnötig aktualisieren möchten.
Tripleee
5
Sie können awk verwenden, um dies wie folgt zu lösen:
Funktioniert auf MacOs ohne Probleme! Alle sedbasierten Befehle schlugen fehl, wenn Binärdateien auch mit den osx-spezifischen Einstellungen enthalten waren.
Jankapunkt
Vorsicht ... dies wird explodieren, wenn eine der zurückgegebenen Dateien findein Leerzeichen in ihrem Namen hat! Es ist viel sicherer zu verwenden while read: stackoverflow.com/a/9612560/1938956
Soren Bjornstad
5
Einfachster Weg zum Ersetzen ( alle Dateien, Verzeichnis, rekursiv )
find .-type f -not -path '*/\.*'-exec sed -i 's/foo/bar/g'{}+
Hinweis: Manchmal müssen Sie möglicherweise einige versteckte Dateien ignorieren, dh .gitSie können den obigen Befehl verwenden.
Wenn Sie versteckte Dateien einschließen möchten, verwenden Sie,
find .-type f -exec sed -i 's/foo/bar/g'{}+
In beiden Fällen wird die Zeichenfolge foodurch eine neue Zeichenfolge ersetztbar
Hallo @RikHic, netter Tipp - habe über so etwas nachgedacht; Leider hat sich die obige Formatierung nicht ganz als richtig herausgestellt :) Also werde ich es mit einem Pre-Tag versuchen (funktioniert nicht) - also mit entkommenden Backticks: sed -i 's/subdomainA/subdomainB/g'` grep -ril 'subdomainA' /home/www/*` - das sieht immer noch nicht allzu gut aus, sollte aber Copypaste überleben :) Prost!
Sdaau
4
#!/usr/local/bin/bash -x
find */home/www -type f |while read files
do
sedtest=$(sed -n '/^/,/$/p'"${files}"| sed -n '/subdomainA/p')if["${sedtest}"]then
sed s'/subdomainA/subdomainB/'g "${files}">"${files}".tmp
mv "${files}".tmp "${files}"fidone
Suchen Sie rekursiv nach der Zeichenfolge, die Sie in einem bestimmten Pfad ersetzen möchten, und nehmen Sie nur den vollständigen Pfad der übereinstimmenden Datei. (das wäre das $(grep 'string' 'pathname' -Rl).
(optional) Wenn Sie eine Vorsicherung dieser Dateien in einem zentralen Verzeichnis erstellen möchten, können Sie dies möglicherweise auch verwenden: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
Danach können Sie nach Belieben vimein Schema bearbeiten / ersetzen , das dem unter dem angegebenen Link angegebenen ähnelt:
Ein bisschen altmodisch, aber das hat unter OS X funktioniert.
Es gibt nur wenige Tricks:
• Bearbeitet nur Dateien mit der Erweiterung .slsim aktuellen Verzeichnis
• .muss maskiert werden, um sicherzustellen, dass sedsie nicht als "irgendein Zeichen" bewertet werden.
• ,wird sedanstelle des üblichen als Trennzeichen verwendet/
Beachten Sie auch, dass Sie eine Jinja-Vorlage bearbeiten müssen, um eine variableim Pfad einer zu übergeben import(dies ist jedoch kein Thema).
Überprüfen Sie zunächst, ob Ihr Befehl sed das tut, was Sie möchten (dies druckt nur die Änderungen an stdout, die Dateien werden nicht geändert):
for file in $(find .-name *.sls -type f);do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file;done
Bearbeiten Sie den Befehl sed nach Bedarf, sobald Sie bereit sind, Änderungen vorzunehmen:
for file in $(find .-name *.sls -type f);do echo -e "\n$file: "; sed -i '''s,foo\.bar,foo/bar/\"+baz+\"/,g' $file;done
Beachten Sie , dass ich -i ''im Befehl sed keine Sicherungskopie der Originaldateien erstellen wollte (wie in In-Place-Änderungen mit sed unter OS X oder in Robert Lujos Kommentar auf dieser Seite erläutert ).
plus eins für `'*. [c | cc | cp | cpp | m | mm | h]'`
FractalSpace
2
Hier ist eine Version, die allgemeiner sein sollte als die meisten anderen. es erfordert zum Beispiel nicht find( dustattdessen). Es erfordert xargs, die nur in einigen Versionen von Plan 9 (wie 9front) zu finden sind.
du -a | awk -F' ''{ print $2 }'| xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Wenn Sie Filter wie Dateierweiterungen hinzufügen möchten, verwenden Sie grep:
du -a | grep "\.scala$"| awk -F' ''{ print $2 }'| xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Dies hat einige lästige Probleme beim Zitieren sowie beim Lesen von Zeilen mit for.
Tripleee
1
Wenn Sie dies verwenden möchten, ohne Ihr SVN-Repository vollständig zu zerstören, können Sie 'find' anweisen, alle versteckten Dateien zu ignorieren, indem Sie Folgendes tun:
find . \( !-regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'
Die Klammern scheinen überflüssig zu sein. Dies hatte zuvor einen Formatierungsfehler, der es unbrauchbar machte (das Markdown-Rendering würde einige Zeichen aus dem regulären Ausdruck verschlingen).
Tripleee
1
Mit Kombination von grepundsed
for pp in $(grep -Rl looking_for_string)do
sed -i 's/looking_for_string/something_other/g'"${pp}"done
@tripleee Ich habe das ein bisschen modifiziert. In diesem Fall Ausgabe für Befehl grep -Rl patterngenerierte Liste von Dateien, in denen sich das Muster befindet. Dateien werden nicht in einer forSchleife gelesen .
Pawel
Huh? Sie haben noch eine forSchleife; Wenn ein zurückgegebener Dateiname Leerzeichen enthält, funktioniert dies nicht ordnungsgemäß, da die Shell die forArgumentliste mit einem Token versehen kann . Aber dann verwenden Sie die Dateinamenvariable ohne Anführungszeichen innerhalb der Schleife, sodass sie dort stattdessen unterbrochen wird, wenn Sie dies beheben. Das Korrigieren dieser verbleibenden Fehler würde Ihre mit der Antwort von @ MadMan2064 identisch machen.
Tripleee
@tripleee ja, das stimmt, ich habe das verpasst.
Pawel
1
Zum Ersetzen aller Vorkommen in einem Git-Repository können Sie Folgendes verwenden:
git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
Siehe Listendateien im lokalen Git-Repo? für andere Optionen zum Auflisten aller Dateien in einem Repository. Die -zOptionen weisen git an, die Dateinamen mit einem Null-Byte zu trennen, wodurch sichergestellt wird, dass xargs(mit der Option -0) Dateinamen getrennt werden können, selbst wenn sie Leerzeichen oder ähnliches enthalten.
-path ./.git -prune -o
infind . -path ./.git -prune -o -type f -name '*matchThisText*' -print0
vor dem xargs kochendAntworten:
-print0
weistfind
an, jedes der Ergebnisse durch ein Nullzeichen anstatt durch eine neue Zeile zu drucken. In dem unwahrscheinlichen Fall, dass Ihr Verzeichnis Dateien mit Zeilenumbrüchen in den Namen enthält, können Sie dennochxargs
die richtigen Dateinamen bearbeiten.\( -type d -name .git -prune \)
ist ein Ausdruck, der alle genannten Verzeichnisse vollständig überspringt.git
. Sie können es leicht erweitern, wenn Sie SVN verwenden oder andere Ordner haben, die Sie beibehalten möchten - stimmen Sie einfach mit mehr Namen überein. Es ist ungefähr gleichwertig-not -path .git
, aber effizienter, da es nicht jede Datei im Verzeichnis überprüft, sondern vollständig überspringt. Das-o
Nachher ist erforderlich, weil es-prune
tatsächlich funktioniert.Weitere Informationen finden Sie unter
man find
.quelle
sed: 1: "...": invalid command code .
Probleme auftreten. Es scheint, dass die Option -i eine Erweiterung erwartet und den's/../...'
Befehl parses ausgibt . Lösung: Übergeben Sie die Erweiterung '' an die Option -i wiesed -i '' 's/...
.svn st
keine Änderungen angezeigt werden, liegt dies daran, dass Sie auch Dateien in den .svn-Verzeichnissen geändert haben! Verwenden Siefind . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'
stattdessen.grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'
, um zu vermeiden, dass nicht verwandte Dateien bearbeitet werden (sed kann die Dateicodierung ändern).find .git ... | ... 'sed -i s/(the opposite from before)/g'
deinen Git-Index reparierenHinweis : Führen Sie diesen Befehl nicht in einem Ordner aus, der ein Git-Repo enthält. Änderungen an .git können Ihren Git-Index beschädigen.
Im Vergleich zu anderen Antworten hier ist dies einfacher als die meisten anderen und verwendet sed anstelle von perl, was in der ursprünglichen Frage gefordert wurde.
quelle
-i
Option von sed ein explizites leeres String-Argument geben müssen . dh:sed -i '' 's/original/replacement/g'
+
wird die Anzahl der erzeugtensed
Prozesse erheblich reduziert . Es ist effizienter.find . -not -path '*/\.git*' -type f ...
.Der einfachste Weg für mich ist
quelle
-I
oder--binary-file=without-match
grep..svn
. Zum Beispiel:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
brew install gnu-sed
undgsed
unter OSX verwenden, um eine Welt voller Schmerzen zu vermeiden.git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
. Es ist überhaupt nicht schön, dein.git
DirAlle Tricks sind fast gleich, aber ich mag diesen:
find <mydir>
: im Verzeichnis nachschlagen.-type f
::-exec command {} +
::quelle
file
Befehl verwenden, um zu versuchen, den Dateityp jeder Datei zu bestimmen, aber die zufälligen Abweichungen in der Ausgabe können etwas verwirrend sein. Die-I
(aka--mime
) Option hilft etwas, oder--mime-type
wenn Sie das haben. Wie genau man diesen ordentlichen Einzeiler umgestaltet, um dies zu tun, ist für dieses winzige Kommentarfeld leider nicht möglich. Vielleicht eine separate Frage stellen, wenn Sie Hilfe benötigen? (Vielleicht fügen Sie dann hier einen Kommentar mit einem Link hinzu.)quelle
-print0
undxargs
anstelle von-exec
oder-execdir
?find -exec command {} +
- es vermeidet übermäßige Aufrufe des Befehls wie xargs, jedoch ohne den separaten Prozess.find -exec ... {} +
ist seit 2006 POSIX-spezifiziert.Für mich ist https://stackoverflow.com/a/2113224/565525 die am einfachsten zu merkende Lösung , dh:
HINWEIS : Behebt
-i ''
das OSX-Problemsed: 1: "...": invalid command code .
HINWEIS : Wenn zu viele Dateien verarbeitet werden müssen, erhalten Sie
Argument list too long
. Die oben beschriebene Problemumgehung - Verwendungfind -exec
oderxargs
Lösung.quelle
workaround
sollte die bevorzugte Syntax in allen Fällen.$(find...)
besteht darin, dass die Shell keine Möglichkeit hat, Dateinamen mit Leerzeichen oder anderen Shell-Metazeichen zu verarbeiten. Wenn Sie wissen, dass dies kein Problem ist, ist dieser Ansatz in Ordnung. Wir haben jedoch zu viele Fragen, bei denen die Leute nicht über dieses Problem gewarnt wurden oder die Warnung nicht verstanden haben.Für alle, die Silver Searcher verwenden (
ag
)Da ag standardmäßig git / hg / svn-Dateien / -Ordner ignoriert, kann dies sicher in einem Repository ausgeführt werden.
quelle
Ein schöner Oneliner als Extra. Mit git grep.
quelle
refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }
Verwendung, zum Beispiel um 'Wort' durch 'Schwert' zu ersetzen:refactor word sword
Überprüfen Sie dann, was es getan hatgit diff
.Um Dateien zu rekursiv zu reduzieren
sed
, können Siegrep
für Ihre Zeichenfolgeninstanz Folgendes tun:Wenn Sie ausführen, werden
man grep
Sie feststellen, dass Sie auch ein--exlude-dir="*.git"
Flag definieren können, wenn Sie das Durchsuchen von Git-Verzeichnissen unterlassen möchten, um Git-Index-Probleme zu vermeiden, wie andere höflich hervorgehoben haben.Sie führen zu:
quelle
Dieser ist mit Git-Repositories kompatibel und etwas einfacher:
Linux:
Mac:
(Dank an http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )
quelle
git-grep
‚s --z
Option zusammen mitxargs -0
.git grep
macht natürlich nur in einemgit
repo Sinn . Der allgemeine Ersatz wäregrep -r
.-z
,git-grep
trennt die Ausgabefelder durch Null-Bytes anstelle von Zeilenumbrüchen. und mit-0
,xargs
liest die Eingabe von Null - Bytes getrennt, statt Leerzeichen (und nicht tun seltsame Dinge mit Anführungszeichen). Wenn Sie also nicht möchten, dass der Befehl unterbrochen wird, wenn die Dateinamen Leerzeichen, Anführungszeichen oder andere lustige Zeichen enthalten, lautet der Befehl :git grep -z -l 'original_text' | xargs -0 sed ...
.find /home/www/ -type f
listet alle Dateien in / home / www / (und seinen Unterverzeichnissen) auf. Das Flag "-exec" weist find an, den folgenden Befehl für jede gefundene Datei auszuführen.ist der Befehl, der für die Dateien ausgeführt wird (viele gleichzeitig). Das
{}
wird durch Dateinamen ersetzt. Am+
Ende des Befehls wird angegebenfind
, dass ein Befehl für viele Dateinamen erstellt werden soll.In der
find
Manpage heißt es: "Die Befehlszeile ist ähnlich aufgebaut wie xargs seine Befehlszeilen."So ist es möglich, Ihr Ziel zu erreichen (und Dateinamen mit Leerzeichen zu behandeln), ohne
xargs -0
oder zu verwenden-print0
.quelle
Ich brauchte das nur und war mit der Geschwindigkeit der verfügbaren Beispiele nicht zufrieden. Also habe ich mir mein eigenes ausgedacht:
Ack-grep ist sehr effizient beim Auffinden relevanter Dateien. Dieser Befehl ersetzte ~ 145 000 Dateien durch einen Kinderspiel, während andere so lange dauerten, dass ich nicht warten konnte, bis sie fertig waren.
quelle
grep -ril 'subdomainA' *
bei weitem nicht so schnell wiegrep -Hr 'subdomainA' * | cut -d: -f1
.Eine einfache Methode, wenn Sie Verzeichnisse (
--exclude-dir=.svn
) ausschließen müssen und möglicherweise auch Dateinamen mit Leerzeichen haben (mit 0Byte mitgrep -Z
undxargs -0
quelle
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
Ich denke, die meisten Leute wissen nicht, dass sie etwas in eine "while read file" leiten können, und es vermeidet diese fiesen -print0-Argumente, während Leerzeichen in Dateinamen beibehalten werden.
Wenn Sie ein
echo
vor dem sed hinzufügen, können Sie sehen, welche Dateien sich ändern, bevor Sie es tatsächlich tun.quelle
-print0
dafür ist, dass Fälle behandelt werden, diewhile read
einfach nicht behandelt werden können. Ein Zeilenumbruch ist ein gültiges Zeichen in einem Unix-Dateinamen. Damit Ihr Code vollständig robust ist, muss er auch mit solchen Dateinamen umgehen. (Außerdem möchten Sieread -r
ein lästiges POSIX-Legacy-Verhalten in vermeidenread
.)sed
ein No-Op, wenn es keine Übereinstimmungen gibt, so dass dasgrep
nicht wirklich notwendig ist; Dies ist jedoch eine nützliche Optimierung, um zu vermeiden, dass Dateien neu geschrieben werden, die keine Übereinstimmungen enthalten, wenn Sie viele davon haben oder Datumsstempel für Dateien nicht unnötig aktualisieren möchten.Sie können awk verwenden, um dies wie folgt zu lösen:
hoffe das wird dir helfen !!!
quelle
sed
basierten Befehle schlugen fehl, wenn Binärdateien auch mit den osx-spezifischen Einstellungen enthalten waren.find
ein Leerzeichen in ihrem Namen hat! Es ist viel sicherer zu verwendenwhile read
: stackoverflow.com/a/9612560/1938956Einfachster Weg zum Ersetzen ( alle Dateien, Verzeichnis, rekursiv )
Hinweis: Manchmal müssen Sie möglicherweise einige versteckte Dateien ignorieren, dh
.git
Sie können den obigen Befehl verwenden.Wenn Sie versteckte Dateien einschließen möchten, verwenden Sie,
In beiden Fällen wird die Zeichenfolge
foo
durch eine neue Zeichenfolge ersetztbar
quelle
Versuche dies:
quelle
sed -i 's/subdomainA/subdomainB/g'
`grep -ril 'subdomainA' /home/www/*
` - das sieht immer noch nicht allzu gut aus, sollte aber Copypaste überleben :) Prost!quelle
Laut diesem Blog-Beitrag:
quelle
/
? Zum Beispiel möchte ich IP-Adressen ersetzen:xxx.xxx.xxx.xxx
fürxxx.xxx.xxx.xxx/folder
/
mit \ entkommen . Zum Beispiel:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
Wenn es Ihnen nichts ausmacht,
vim
zusammen mitgrep
oderfind
Tools zu verwenden, können Sie die Antwort von Benutzer Gert in diesem Link nachverfolgen -> Wie wird ein Textersatz in einer großen Ordnerhierarchie durchgeführt?.Das ist der Deal:
Suchen Sie rekursiv nach der Zeichenfolge, die Sie in einem bestimmten Pfad ersetzen möchten, und nehmen Sie nur den vollständigen Pfad der übereinstimmenden Datei. (das wäre das
$(grep 'string' 'pathname' -Rl)
.(optional) Wenn Sie eine Vorsicherung dieser Dateien in einem zentralen Verzeichnis erstellen möchten, können Sie dies möglicherweise auch verwenden:
cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
Danach können Sie nach Belieben
vim
ein Schema bearbeiten / ersetzen , das dem unter dem angegebenen Link angegebenen ähnelt::bufdo %s#string#replacement#gc | update
quelle
Ein bisschen altmodisch, aber das hat unter OS X funktioniert.
Es gibt nur wenige Tricks:
• Bearbeitet nur Dateien mit der Erweiterung
.sls
im aktuellen Verzeichnis•
.
muss maskiert werden, um sicherzustellen, dasssed
sie nicht als "irgendein Zeichen" bewertet werden.•
,
wirdsed
anstelle des üblichen als Trennzeichen verwendet/
Beachten Sie auch, dass Sie eine Jinja-Vorlage bearbeiten müssen, um eine
variable
im Pfad einer zu übergebenimport
(dies ist jedoch kein Thema).Überprüfen Sie zunächst, ob Ihr Befehl sed das tut, was Sie möchten (dies druckt nur die Änderungen an stdout, die Dateien werden nicht geändert):
Bearbeiten Sie den Befehl sed nach Bedarf, sobald Sie bereit sind, Änderungen vorzunehmen:
Beachten Sie , dass ich
-i ''
im Befehl sed keine Sicherungskopie der Originaldateien erstellen wollte (wie in In-Place-Änderungen mit sed unter OS X oder in Robert Lujos Kommentar auf dieser Seite erläutert ).Viel Spaß beim Säen!
quelle
nur um zu vermeiden, sich auch zu ändern
aber dennoch
(Vielleicht nicht gut in der Idee hinter Domain Root)
quelle
Ich benutze nur Tops:
quelle
Hier ist eine Version, die allgemeiner sein sollte als die meisten anderen. es erfordert zum Beispiel nicht
find
(du
stattdessen). Es erfordertxargs
, die nur in einigen Versionen von Plan 9 (wie 9front) zu finden sind.Wenn Sie Filter wie Dateierweiterungen hinzufügen möchten, verwenden Sie
grep
:quelle
Für Qshell (qsh) unter IBMi nicht Bash, wie von OP markiert.
Einschränkungen von qsh-Befehlen:
Also die Lösung in qsh:
Vorsichtsmaßnahmen:
quelle
for
.Wenn Sie dies verwenden möchten, ohne Ihr SVN-Repository vollständig zu zerstören, können Sie 'find' anweisen, alle versteckten Dateien zu ignorieren, indem Sie Folgendes tun:
quelle
Mit Kombination von
grep
undsed
quelle
grep -Rl pattern
generierte Liste von Dateien, in denen sich das Muster befindet. Dateien werden nicht in einerfor
Schleife gelesen .for
Schleife; Wenn ein zurückgegebener Dateiname Leerzeichen enthält, funktioniert dies nicht ordnungsgemäß, da die Shell diefor
Argumentliste mit einem Token versehen kann . Aber dann verwenden Sie die Dateinamenvariable ohne Anführungszeichen innerhalb der Schleife, sodass sie dort stattdessen unterbrochen wird, wenn Sie dies beheben. Das Korrigieren dieser verbleibenden Fehler würde Ihre mit der Antwort von @ MadMan2064 identisch machen.Zum Ersetzen aller Vorkommen in einem Git-Repository können Sie Folgendes verwenden:
Siehe Listendateien im lokalen Git-Repo? für andere Optionen zum Auflisten aller Dateien in einem Repository. Die
-z
Optionen weisen git an, die Dateinamen mit einem Null-Byte zu trennen, wodurch sichergestellt wird, dassxargs
(mit der Option-0
) Dateinamen getrennt werden können, selbst wenn sie Leerzeichen oder ähnliches enthalten.quelle
quelle
awk
/sed
, aber Perl ist üblich (außer Embedded / Systeme nur mit Busybox).So ändern Sie mehrere Dateien (und speichern ein Backup unter
*.bak
):nimmt alle Dateien im Verzeichnis und ersetzt sie
|
durch x, das als "Perl-Kuchen" bezeichnet wird (einfach wie ein Kuchen).quelle