Der Befehl sed mit der Option -i schlägt unter Mac fehl, funktioniert jedoch unter Linux

303

Ich habe den folgenden sedBefehl erfolgreich verwendet, um Text unter Linux zu suchen / zu ersetzen:

sed -i 's/old_link/new_link/g' *

Wenn ich es jedoch unter Mac OS X versuche, erhalte ich Folgendes:

"Befehl c erwartet \ gefolgt von Text"

Ich dachte, auf meinem Mac läuft eine normale BASH-Shell. Was geht?

BEARBEITEN:

Laut @High Performance liegt dies daran, seddass der Mac eine andere (BSD) Variante hat. Meine Frage wäre daher, wie ich diesen Befehl in BSD repliziere sed.

BEARBEITEN:

Hier ist ein aktuelles Beispiel, das dies verursacht:

sed -i 's/hello/gbye/g' *
Yarin
quelle
1
Dies bedeutet, dass sedein "c" in Ihren Daten als Befehl angezeigt wird. Verwenden Sie eine Variable? Bitte posten Sie etwas, das den tatsächlichen Befehl und einige Daten, die Sie verarbeiten, genauer darstellt. Sie können eine einfache Demonstration dieses Fehlers erhalten, indem Sie dies tun echo x | sed c.
Bis auf weiteres angehalten.
@ Tennis, der einfache Befehl oben verursacht dies, obwohl die Daten, die es verarbeitet, eine ganze Website sind (ich konvertiere alle Bildlinks), einschließlich HTML- und CSS-Dateien ...
Yarin

Antworten:

397

Wenn Sie die -iOption verwenden, müssen Sie eine Erweiterung für Ihre Sicherungen bereitstellen.

Wenn Sie haben:

File1.txt
File2.cfg

Der Befehl (beachten Sie den Platzmangel zwischen -iund ''und -e, damit er auf neuen Versionen von Mac und GNU funktioniert):

sed -i'.original' -e 's/old_link/new_link/g' *

Erstellen Sie 2 Sicherungsdateien wie:

File1.txt.original
File2.cfg.original

Es gibt keine tragbare Möglichkeit, das Erstellen von Sicherungsdateien zu vermeiden, da es unmöglich ist, eine Mischung von sed-Befehlen zu finden, die in allen Fällen funktioniert:

  • sed -i -e ...- funktioniert unter OS X nicht, da -eBackups erstellt werden
  • sed -i'' -e ... - funktioniert nicht unter OS X 10.6, aber unter 10.9+
  • sed -i '' -e ... - arbeitet nicht an GNU

Hinweis Da nicht auf allen Plattformen ein sed-Befehl ausgeführt wird, können Sie versuchen, einen anderen Befehl zu verwenden, um das gleiche Ergebnis zu erzielen.

Z.B, perl -i -pe's/old_link/new_link/g' *

Sinetris
quelle
4
Ich hatte das gleiche Problem. Danke für diese Lösung. Aber wo ich mit 'man sed' versucht habe, die Beschreibung von '-i' zu finden, gibt es nichts über die Verwendung von -i '', um Backups zu ignorieren. Dies ist meine erste Schuld. Zweitens, wenn der Fehler "Befehl erwartet \ gefolgt von Text" angezeigt wird, warum sagt er uns dann nicht direkt, dass er einen Sicherungsnamen für die Option '-i' erwartet !! ?? So etwas passiert überall: Sie erhalten einen Fehler, aber nicht warum der Fehler, dann suchen Sie nach dem Handbuch, das nichts darüber erklärt. Dann googeln Sie es, um jemanden zu finden, der das gleiche Problem hat. Ich meine, warum nicht ein Beispiel im Handbuch geben?
Lukmac
oder sagen Sie uns, warum der Fehler vorliegt, anstatt nur eine informationslose Meldung, dass ein Fehler auftritt. Dies ist ein Vorschlag an alle Werkzeughersteller, falls sie diesen Kommentar jemals lesen können.
Lukmac
5
@lukmac Soweit sich herausstellen sedlässt, haben Sie ein Backup-Suffix angegeben. Das Backup-Suffix lautet s/old_link/new_link/g. Das nächste Argument danach sollen die Bearbeitungsbefehle sein. Da die Befehle als Sicherungsname interpretiert wurden, wurde der erste Dateiname als Bearbeitungsbefehl verwendet, der jedoch nicht gültig war.
Barmar
2
Wird dies immer ein Problem sein? Gibt es eine Möglichkeit, dass Apple in der Lage ist, eine Problemumgehung / ein Paket zu erstellen, das bzw. das mit OSX erstellt wurde? Oder konnte GNU keine Unterstützung leisten sed -i '' -e ...?
Blong
5
sed -i'' -escheint auf Mac
10.14
64

Ich glaube unter OS X, wenn Sie -i verwenden, ist eine Erweiterung für die Sicherungsdateien erforderlich . Versuchen:

sed -i .bak 's/hello/gbye/g' *

Bei Verwendung von GNU ist seddie Erweiterung optional .

Bis auf weiteres angehalten.
quelle
55

Dies funktioniert sowohl mit GNU- als auch mit BSD-Versionen von sed:

sed -i'' -e 's/old_link/new_link/g' *

oder mit Backup:

sed -i'.bak' -e 's/old_link/new_link/g' *

Beachten Sie den fehlenden Platz nach der -iOption! (Notwendig für GNU sed)

Chipiik
quelle
7
Der erste funktioniert nicht unter OSX (ich habe ihn gerade am 10.6.8 getestet)
marcin
4
Für mich unter OS X (10.10.3) hat die erste Sicherungsdatei mit dem Suffix -e erstellt. Nicht gut. Das zweite war das einzige, was zwischen Ubuntu und OS X konsistent für mich funktionierte. Ich wollte jedoch keine Sicherungsdateien, daher musste ich rmdirekt danach einen Befehl ausführen , um es zu löschen.
Brendan
1
Die erste Zeile sollte mit einem Leerzeichen umgeschrieben werden, um am 10.10 zu arbeiten: sed -i'' ...=>sed -i '' ...
Daniel Jomphe
3
@ DanielJomphe Aber das Hinzufügen dieses Leerzeichens funktioniert nicht auf GNU sed
Brice
1
@marcin first funktioniert auch für mich unter OSX 10.11.2. Das einzige ist, dass eine Sicherungsdatei erstellt wird, die anschließend entfernt werden muss. Zweitens sieht es besser aus, da wir den Dateinamen später nicht herausfinden müssen.
Vikas027
41

Hatte das gleiche Problem in Mac und löste es mit brew:

brew install gnu-sed

und verwenden als

gsed SED_COMMAND

Sie können sowohl als auch sedals Alias festlegen gsed(wenn Sie möchten):

alias sed=gsed
Sruthi Poddutur
quelle
3
Warum haben Sie genau die gleiche Antwort gegeben wie Ohad Kravchick ?
gniourf_gniourf
1
Ein
solcher
1
Fügen Sie anstelle eines Alias, wie auf der entsprechenden Brew-Seite empfohlen, diesen zum Pfad hinzu: PATH = "$ (Brew - Präfix) / opt / gnu-sed / libexec / gnubin: $ PATH"
y.luis
24

Sie können auch die GNU-Version von sed auf Ihrem Mac installieren, die als gsed bezeichnet wird, und sie mit der Standard-Linux-Syntax verwenden.

Installieren Sie dazu gsedüber Ports (wenn Sie diese nicht haben, rufen Sie sie unter http://www.macports.org/ auf ), indem Sie sie ausführen sudo port install gsed. Dann kannst du rennensed -i 's/old_link/new_link/g' *

Ohad Kravchick
quelle
24
.. oder wenn Sie Homebrew verwenden, dann installieren Siegnu-sed
Sudar
1
Danke @Sudar, doppelte Daumen hoch!
Andrew Swan
9

Auf Ihrem Mac wird zwar eine BASH-Shell ausgeführt, dies ist jedoch eher eine Frage der Implementierung von sed, mit der Sie sich befassen. Auf einem Mac stammt sed von BSD und unterscheidet sich geringfügig von dem sed, das Sie auf einer typischen Linux-Box finden. Ich schlage dich vor man sed.

Hochleistungsmarke
quelle
3
Vielen Dank, dass Sie auf das BSD-Problem hingewiesen haben. Aber ich bin ziemlich Analphabet und brauche nur eine schnelle Lösung für meinen Befehl. Ein kurzer Blick auf den Menschen sagt mir nichts
Yarin
5
@Yarin - nein, und wenn ich einen kurzen Blick auf man sed wirft, sagt dir das auch nichts. Versuchen Sie einen längeren Blick.
Hochleistungsmarke
21
Die meisten SO-Antworten sind irgendwo in einem Mann vergraben, aber genau das ist SO für vielbeschäftigte Menschen, die Antworten von klugen Leuten brauchen
Yarin
9

Die Antwort von Sinetris ist richtig, aber ich verwende diesen findBefehl mit, um genauer zu bestimmen, welche Dateien ich ändern möchte. Im Allgemeinen sollte dies funktionieren (getestet auf osx /bin/bash):

find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;

Im Allgemeinen ist die Verwendung sedohne findin komplexen Projekten weniger effizient.

Lucas
quelle
-execist sehr nett! Ich frage mich nur, ob der Schrägstrich am Ende tatsächlich nötig ist
Ye Liu
2
@YeLiu: ohne das \wurde das ;von der Shell interpretiert, als ich es versuchte
serv-inc
2

Ich habe eine Funktion erstellt, um den sedUnterschied zwischen MacOS (getestet unter MacOS 10.12) und anderen Betriebssystemen zu behandeln:

OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
    if [ "$OS" = 'Darwin' ]; then
        # for MacOS
        sed -i '' -e "$1" "$2"
    else
        # for Linux and Windows
        sed -i'' -e "$1" "$2"
    fi
}

Verwendungszweck:

$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")

Wo:

, ist ein Delimeter

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' ist Muster

"./mysql/.env" ist der Pfad zur Datei

v.babak
quelle
1

Hier erfahren Sie, wie Sie Umgebungsvariablen auf die Vorlagendatei anwenden (keine Sicherung erforderlich).

1. Erstellen Sie eine Vorlage mit {{FOO}} zum späteren Ersetzen.

echo "Hello {{FOO}}" > foo.conf.tmpl

2. Ersetzen Sie {{FOO}} durch die FOO-Variable und geben Sie sie in die neue Datei foo.conf aus

FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf

Funktioniert sowohl mit macOS 10.12.4 als auch mit Ubuntu 14.04.5

katopz
quelle
0

Wie die anderen Antworten zeigen, gibt es keine Möglichkeit, sed portabel unter OS X und Linux zu verwenden, ohne Sicherungsdateien zu erstellen. Also habe ich stattdessen diesen Ruby-Einzeiler verwendet, um dies zu tun:

ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml

In meinem Fall musste ich es von einer rakeAufgabe aus aufrufen (dh innerhalb eines Ruby-Skripts), also habe ich diese zusätzliche Zitierstufe verwendet:

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}
Dan Kohn
quelle
-1
sed -ie 's/old_link/new_link/g' *

Funktioniert sowohl unter BSD als auch unter Linux

Ashokrajar
quelle
3
Dies erstellt unter Linux einen anderen Dateinamen mit eangehängten
Brice
1
Gebrochen, besser zu entfernen.
Sorin
Es funktioniert unter Mac und Linux. Was ist das Problem mit dieser Lösung?
Islam Azab
Nein, es funktioniert nicht auf Mac BSD Sed - es würde eine Sicherungsdatei mit 'e' zum Dateinamen erstellen.
Jesper Grann Laursen