Rekursives Suchen und Ersetzen in Textdateien unter Mac und Linux


127

In der Linux-Shell sucht und ersetzt der folgende Befehl rekursiv alle Instanzen von 'this' durch 'that' (ich habe keine Linux-Shell vor mir, sollte es aber tun).

find . -name "*.txt" -print | xargs sed -i 's/this/that/g'

Wie sieht ein ähnlicher Befehl unter OSX aus?


Sollte wahrscheinlich verschoben werden, apple.stackexchange.comda es weder für Linux noch für alle Entwickler generisch genug ist.
AlikElzin-Kilaka

Antworten:


246

OS X verwendet eine Mischung aus BSD- und GNU-Tools. Überprüfen Sie daher am besten immer die Dokumentation (obwohl ich sie hatte, lessdie nicht einmal der OS X-Manpage entsprach):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html

sed nimmt das Argument nach -ials Erweiterung für Backups. Geben Sie eine leere Zeichenfolge ( -i '') für keine Sicherungen an.

Folgendes sollte reichen:

LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +

Das -type fist nur eine gute Praxis; sed wird sich beschweren, wenn Sie ihm ein Verzeichnis oder so geben. -execwird gegenüber bevorzugt xargs; Sie brauchen sich nicht darum zu kümmern -print0oder so. Das {} +am Ende bedeutet, dass findalle Ergebnisse als Argumente an eine Instanz des aufgerufenen Befehls angehängt werden, anstatt sie für jedes Ergebnis erneut auszuführen. (Eine Ausnahme ist, wenn die vom Betriebssystem maximal zulässige Anzahl von Befehlszeilenargumenten verletzt wird. In diesem Fall findwird mehr als eine Instanz ausgeführt.)


2
Mein "dies" in dieser Ersetzung enthält einen Schrägstrich (localhost / site). Ich ersetze Teile einer URL in einer HTML-Datei. Wie kann ich eine solche Ersetzung vornehmen? Ich habe versucht, doppelte Anführungszeichen zu setzen, aber es schlägt fehl.
Timothy T.

6
Die Sed-Syntax ermöglicht die Verwendung fast aller Zeichen anstelle des Schrägstrichs, z. B. können Sie das %Zeichen verwenden : sed "s%localhost/site%blah/blah%". Eine andere Alternative besteht darin, das Trennzeichen rückwärts zu entfernen : sed "s/localhost\/site/blah\/blah/".
TaylanUB

Danke, lass mich das versuchen. Ich habe jedoch versucht, den Schrägstrich mit {} zu trennen, und es ist immer noch ein Fehler aufgetreten ...
Timothy T.

16
Bekommt sonst noch jemand einen illegal byte sequenceFehler? Wenn ja, versuchen Sie es: LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +Es hat bei mir funktioniert.
ColdTuna

10
Dies wird nur eine Währung pro Datei ersetzen, /gfür mehrere Währung wieLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
Jamesjara

152

Für den Mac wäre ein ähnlicher Ansatz folgender:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"

10
Ich wünschte, ich könnte dies jedes Mal verbessern, wenn ich darauf zurückkomme und es benutze. Es wäre jetzt bei +15, einfach.
Droogans

Aus irgendeinem Grund funktioniert es bei mir nicht. Es macht nichts. Ich bin im Ordner form360 und versuche, alle String-Instanzen mit dem Namen easyform in form360 zu ändern. Ich führe den folgenden Befehl aus:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos

2
Für mich sollte dies die richtige Antwort sein. Es ist das einzige, das für mich funktioniert hat.
Nosequeldeebee

1
-print0 | xargs -0 funktioniert auf meinem Mac nicht, wenn der Dateiname Leerzeichen enthält.
user2807219

1
sed:.: In-Place-Bearbeitung funktioniert nur für reguläre Dateien
Codeslapper

14

Als alternative Lösung verwende ich diese unter Mac OSX 10.7.5

grep -ilr 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

Gutschrift geht an: Todd Cesere Antwort


Dieser funktioniert gut! Andere Skripte fügen in einigen Fällen unter OSX ein zusätzliches Zeilenende hinzu! Vielen Dank!
Sebastien Filion

14

Unter Mac OS X 10.11.5 funktioniert dies einwandfrei:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

xargs -I @ sed -i '' s / altes Wort / neues Wort / g '@ hat für mich funktioniert, nachdem ich so viele andere nicht funktionierende Vorschläge ausprobiert hatte. Danke dir!
DrB

13

Keine der oben genannten Funktionen funktioniert unter OSX.

Mach Folgendes:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt

1
Wie kann man '/' gestalten, wenn SEARCH_FOR und REPLACE_WITH Pfade sind?
rraallvv

Verwenden Sie ein anderes Trennzeichen. Wenn Sie Pfade verwenden, funktioniert ein Doppelpunkt oder eine Pipe. Zum Beispiel 's | SEARCH | REPLACE | g'. Wir verwenden geschweifte Klammern, wie in 's {SEARCH} {REPLACE}'.
Dannysauer

1
dito Frage, versuchen Sie es nicht auf dem Mac - aber es scheint einen Fehler zu generieren? Zum Beispiel wird mein Pfad als Datei interpretiert? -bash: localhost / nohost: Keine solche Datei oder Verzeichnis
Timothy T.

Dies wird nicht durch tiefe Ordner wiederholt. Nur eine Ebene.
Sergey Romanov

Für weitere Informationen zu diesem Befehl lesen Sie lifehacker.com/5810026/...
kuzdu

7

Eine Version, die sowohl unter Linux als auch unter Mac OS X funktioniert (durch Hinzufügen des -eSchalters zu sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'

Ich musste den Export aus dieser Antwort + die Zeile aus der akzeptierten Antwort durchführen (ich wollte nicht, dass Sicherungsdateien generiert werden)
Lance

2
Um den Fehler "Unzulässige Byte-Sequenz" zu beheben, versuchen Sie, die LOCALE einzustellen, bevor Sie den folgenden Befehl export LC_CTYPE=C && export LANG=C
ausführen

Führen Sie dies niemals mit '*' anstelle von '* .filetype' aus, wie ich es getan habe, wenn Sie Git verwenden. Oder Sie können sich von all Ihren unveröffentlichten Arbeiten verabschieden.
Sergey

1
Die Mac-Version des Befehls sed erfordert ein '' nach dem -i, daher ist diese Antwort falsch
G Huxley

2

Wenn ich diesen Befehl eingebe, scheine ich ihn immer abzuspritzen oder eine Flagge zu vergessen. Ich habe einen Gist auf Github basierend auf TaylanUBs Antwort erstellt, der einen globalen Fund aus dem aktuellen Verzeichnis ersetzt. Dies ist Mac OSX-spezifisch.

https://gist.github.com/nateflink/9056302

Es ist schön, weil ich jetzt einfach ein Terminal öffne und kopiere:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

Sie können einige seltsame Byte-Sequenzfehler erhalten, daher hier der vollständige Code:

#!/bin/bash
#By Nate Flink

#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: ./$0 [find string] [replace string]"
  exit 1
fi

FIND=$1
REPLACE=$2

#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;

#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|${FIND}|${REPLACE}|g" {} +
exit 0

2

Dies ist meine praktikable. unter Mac OS X 10.10.4

grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'

Die oben genannten, die find verwenden , ändern die Dateien, die den Suchtext nicht enthalten (fügen Sie am Ende der Datei eine neue Zeile hinzu), was ausführlich ist.


2

Wenn Sie ein zsh-Terminal verwenden, können Sie Wildcard-Magie verwenden:

sed -i "" "s/search/high-replace/g" *.txt


1

Ich habe dieses Format verwendet - aber ... ich musste es mindestens drei Mal ausführen, damit es tatsächlich jede Instanz ändert, die ich als äußerst seltsam empfand. Wenn Sie es einmal ausführen, werden einige in jeder Datei geändert, aber nicht alle. Wenn Sie zwei- bis viermal genau dieselbe Zeichenfolge ausführen, werden alle Instanzen abgefangen.

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +

Sie mussten diesen Befehl mehrmals ausführen g, da Ihr sed regex am Ende a benötigt, andernfalls ersetzt er nur das erste Vorkommen thistextin einer Zeile. Ihr Regex sollte also seins/thistext/newtext/g
Les Nightingill

0

https://bitbucket.org/masonicboom/serp ist ein unter OSX getestetes Dienstprogramm go (dh plattformübergreifend), das rekursives Suchen und Ersetzen von Text in Dateien in einem bestimmten Verzeichnis durchführt und jede Ersetzung bestätigt. Es ist neu, könnte also fehlerhaft sein.

Die Verwendung sieht aus wie:

$ ls test
a  d  d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"                         
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye

0
find . -type f | xargs sed -i '' 's/string1/string2/g'

Weitere Informationen finden Sie hier .


-3

Der Befehl unter OSX sollte genau der gleiche sein wie Unix unter der hübschen Benutzeroberfläche.


Das habe ich mir gedacht, aber nein. Beim Einspeisen in sed wird ein ./ vor die Dateien gestellt, sodass sed den "ungültigen Befehlscode" beanstandet. Vielleicht bin ich nur müde ;-)
Jack

@JacobusR, bitte ausschneiden und einfügen von Ihrem OSX-Terminal - Sie müssen etwas anderes eingeben.
Glenn Jackman

3
Möglicherweise möchten Sie -print0den findFlags und -0den xargsFlags hinzugefügt werden .
Jmtd

Sie können auch nur -exec sed -i s/this/that/g {} \+anstelle von -printund xargs verwenden
Marian

@JacobusR - das funktioniert, auch wenn es einen führenden './' Pfadnamen gibt. Wenn der Dateiname jedoch ein Leerzeichen enthält, z. B. "./jacobus \ R.txt", wird bei der Verwendung von xargsmöglicherweise das durch Leerzeichen getrennte "./jacobus" als Datei angezeigt, an die übergeben werden soll sed, und dann mit "R.txt". , von denen keines existiert.
Brett Hale

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.