Wie führe ich eine rekursive Suche / Ersetzung einer Zeichenfolge durch awk oder sed durch?

673

Wie finde und ersetze ich jedes Vorkommen von:

subdomainA.example.com

mit

subdomainB.example.com

in jeder Textdatei unter dem /home/www/Verzeichnisbaum rekursiv?

Tedd
quelle
93
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.

Weitere Informationen finden Sie unter man find.

Schilfwolf
quelle
132
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.

John Zwinck
quelle
50
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
quelle
1
@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
quelle
@ user2284570 mit -exec? Versuchen Sie, den Pfad auf die ausführbare Datei anstelle eines Werkzeugnamens festzulegen.
I159
@ I159: Nein: Ausführbare Binärdateien ausschließen (aber Shell-Skripte einschließen) .
user2284570
8
@ 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'
Angestellt Russisch
quelle
2
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.
Charles Duffy
34

Für mich ist https://stackoverflow.com/a/2113224/565525 die am einfachsten zu merkende Lösung , dh:

sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)

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 - Verwendung find -execoder xargsLösung.

Robert Lujo
quelle
4
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.
Tripleee
30

Für alle, die Silver Searcher verwenden ( ag)

ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'

Da ag standardmäßig git / hg / svn-Dateien / -Ordner ignoriert, kann dies sicher in einem Repository ausgeführt werden.

Jacob Wang
quelle
16

Ein schöner Oneliner als Extra. Mit git grep.

git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
Jimmy Kane
quelle
3
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
Domdambrogia
quelle
13

Dieser ist mit Git-Repositories kompatibel und etwas einfacher:

Linux:

git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'

Mac:

git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'

(Dank an http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )

seddonym
quelle
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.

perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

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.

unutbu
quelle
8

Ich brauchte das nur und war mit der Geschwindigkeit der verfügbaren Beispiele nicht zufrieden. Also habe ich mir mein eigenes ausgedacht:

cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

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.

Henno
quelle
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'
Inetphantom
quelle
5

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.

MadMan2064
quelle
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:

for file in `find /home/www -type f`
do
   awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done

hoffe das wird dir helfen !!!

Sarath Kumar
quelle
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

Sazzad Hissain Khan
quelle
4

Versuche dies:

sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`
RikHic
quelle
1
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}"
    fi

done
petrus4
quelle
4

Laut diesem Blog-Beitrag:

find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'
J.Hpour
quelle
Wie entkommen Sie Schrägstrichen /? Zum Beispiel möchte ich IP-Adressen ersetzen: xxx.xxx.xxx.xxxfürxxx.xxx.xxx.xxx/folder
Pathros
Sie können dem /mit \ entkommen . Zum Beispiel:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
J.Hpour
3

Wenn es Ihnen nichts ausmacht, vimzusammen mit grepoder findTools 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 vimein Schema bearbeiten / ersetzen , das dem unter dem angegebenen Link angegebenen ähnelt:

    • :bufdo %s#string#replacement#gc | update
mzcl-mn
quelle
2

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 ).

Viel Spaß beim Säen!

Raphvanns
quelle
2

nur um zu vermeiden, sich auch zu ändern

  • Fast SubdomainA.example.com
  • subdomainA.example.comp.other

aber dennoch

  • subdomainA.example.com.IsIt.good

(Vielleicht nicht gut in der Idee hinter Domain Root)

find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;
NeronLeVelu
quelle
2

Ich benutze nur Tops:

find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 |  xargs -0 tops -verbose  replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)" 
tgunr
quelle
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'
bbarker
quelle
1

Für Qshell (qsh) unter IBMi nicht Bash, wie von OP markiert.

Einschränkungen von qsh-Befehlen:

  • find hat nicht die Option -print0
  • xargs hat keine Option -0
  • sed hat keine -i Option

Also die Lösung in qsh:

    PATH='your/path/here'
    SEARCH=\'subdomainA.example.com\'
    REPLACE=\'subdomainB.example.com\'

    for file in $( find ${PATH} -P -type f ); do

            TEMP_FILE=${file}.${RANDOM}.temp_file

            if [ ! -e ${TEMP_FILE} ]; then
                    touch -C 819 ${TEMP_FILE}

                    sed -e 's/'$SEARCH'/'$REPLACE'/g' \
                    < ${file} > ${TEMP_FILE}

                    mv ${TEMP_FILE} ${file}
            fi
    done

Vorsichtsmaßnahmen:

  • Die Lösung schließt die Fehlerbehandlung aus
  • Nicht Bash wie von OP markiert
Christoff Erasmus
quelle
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'
Marcus Floyd
quelle
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
Pawel
quelle
@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.

Perseiden
quelle
1
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`
Sheena
quelle
1
Nicht mit awk/ sed, aber Perl ist üblich (außer Embedded / Systeme nur mit Busybox).
Pevik
1

So ändern Sie mehrere Dateien (und speichern ein Backup unter *.bak):

perl -p -i -e "s/\|/x/g" *

nimmt alle Dateien im Verzeichnis und ersetzt sie |durch x, das als "Perl-Kuchen" bezeichnet wird (einfach wie ein Kuchen).

Stenemo
quelle
Nicht rekursiv durch Verzeichnisse.
PKHunter
Es ist möglich, darauf zu leiten, was es sehr anpassbar macht, auch über Verzeichnisse. josephscott.org/archives/2005/08/… und unix.stackexchange.com/questions/101415/…
Stenemo