Ersetzen Sie die gesamte Zeile mit einer Zeichenfolge durch Sed

319

Ich habe eine Textdatei, die eine bestimmte Zeile hat

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

Ich muss die ganze Zeile oben durch ersetzen

This line is removed by the admin.

Das Suchwort lautet TEXT_TO_BE_REPLACED

Ich muss dafür ein Shell-Skript schreiben. Wie kann ich das mit erreichen sed?

Rahul
quelle
@Scharron Ich habe versucht, sed -rne 's / (TEXT_TO_BE_REPLACED) \ s + \ w + / \ 1 yyy / xxx' Aber das würde nur yyy durch xxx in der Zeichenfolge ersetzen, wenn ein yyy vorhanden ist. In meinem Fall ist der Text nicht festgelegt ... alles was ich habe ist TEXT_TO_BE_REPLACED.
Rahul
Das ist kein gültiger sed-Ausdruck. Bist du sicher, dass du es mit sed willst? Jede Programmiersprache mit guten regulären Ausdrücken kann einen Ersatz für Sie durchführen (Suche nach einer Unterfunktion). Das wäre einfacher, als sich selbst zu verstehen
Scharron
@Scharron Nun, es wird mit Shell-Skript gemacht, also denke ich, dass sed meine beste Wahl ist.
Rahul

Antworten:

482

Sie können den Befehl change verwenden , um die gesamte Zeile zu ersetzen, und das -iFlag, um die Änderungen an Ort und Stelle vorzunehmen. Zum Beispiel mit GNU sed:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo
Todd A. Jacobs
quelle
4
Beachten Sie, dass Sie vor dem c \ ein Leerzeichen benötigen. Ich habe gerade bearbeitet, um dies hinzuzufügen.
Marcus Downing
27
@MarcusDowning GNU sed benötigt keinen Platz; es funktioniert gut wie ursprünglich gepostet. Wenn Ihr bestimmtes sed den Platz benötigt, notieren Sie auf jeden Fall, welches sed nicht kompatibel ist, und fügen Sie den erforderlichen Aufruf als Kommentar hinzu. Bitte ändern Sie jedoch nicht den Arbeitscode in einer akzeptierten Antwort.
Todd A. Jacobs
7
Wie kann ich eine Variable anstelle des Textes "This ..." verwenden? Wenn ich es durch $ variable ersetze, druckt es nicht seinen Inhalt, sondern den Variablennamen.
Steven
18
Es gibt ein Problem, c\ wenn direkt eine Variable folgt: …c\$VAR…Der Backslash entgeht dem Dollar. In diesem Fall I (bash / sed auf Ubuntu 15.10) schreiben mußte…c\\$VAR…
Jan
6
auf einem Mac verwenden : sed -i '' '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo; (Wenn der erste Parameter leer ist, wird die Datei bearbeitet, andernfalls wird ein Backup erstellt.)
AndreDurao
152

Sie müssen .*vorher und nachher wildards ( ) verwenden, um die gesamte Zeile zu ersetzen:

sed 's/.*TEXT_TO_BE_REPLACED.*/This line is removed by the admin./'
Thor
quelle
Vielen Dank, ich habe gearbeitet: sed 's /.* <Ausdruck>. * / <Ausdruck> SE_LABEL = ABC <Ausdruck> / g' MYR2.xml> test.txt
Nasri Najib
9
Dies funktioniert unter Mac OS X Yosemite mit der Ausnahme, dass ich die Flags -i und -e wie folgt verwende:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Kent Bull
1
@ KentJohnson Ich denke, Sie haben nicht übereinstimmende Anführungszeichen in Ihrem Befehl.
HashHazard
@ MBarnett Sie haben Recht, ich sollte dort zwei doppelte Anführungszeichen haben.
Kent Bull
2
Nur für die vollständige Info. Um es an Ort und Stelle zu machen, kann man -iOption hinzufügen
Temak
20

Die akzeptierte Antwort hat bei mir aus mehreren Gründen nicht funktioniert:

  • Meine Version von sed mag es nicht -imit einer Verlängerung ohne Länge
  • Die Syntax des c\Befehls ist seltsam und ich konnte ihn nicht zum Laufen bringen
  • Ich wusste nicht, dass einige meiner Probleme von ungehinderten Schrägstrichen herrühren

Hier ist die Lösung, die ich gefunden habe und die meiner Meinung nach in den meisten Fällen funktionieren sollte:

function escape_slashes {
    sed 's/\//\\\//g' 
}

function change_line {
    local OLD_LINE_PATTERN=$1; shift
    local NEW_LINE=$1; shift
    local FILE=$1

    local NEW=$(echo "${NEW_LINE}" | escape_slashes)
    sed -i .bak '/'"${OLD_LINE_PATTERN}"'/s/.*/'"${NEW}"'/' "${FILE}"
    mv "${FILE}.bak" /tmp/
}

Die Beispielverwendung zur Behebung des Problems warf also Folgendes auf:

change_line "TEXT_TO_BE_REPLACED" "This line is removed by the admin." yourFile
Skensell
quelle
18

Die Antwort oben:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

Funktioniert einwandfrei, wenn die Ersatzzeichenfolge / -zeile keine Variable ist.

Das Problem ist, dass auf Redhat 5 die \nach der cFlucht die $. Ein Double \\hat auch nicht funktioniert (zumindest bei Redhat 5).

Durch Treffer und Gerichtsverfahren entdeckte ich, dass die \ nach der cüberflüssig ist , wenn Ihr Ersatz - String / Zeile nur eine einzige Zeile ist. Also habe ich \nach dem nicht verwendet c, eine Variable als einzelne Ersatzzeile verwendet und es war Freude.

Der Code würde ungefähr so ​​aussehen:

sed -i "/TEXT_TO_BE_REPLACED/c $REPLACEMENT_TEXT_STRING" /tmp/foo

Beachten Sie die Verwendung von doppelten Anführungszeichen anstelle von einfachen Anführungszeichen.

user4256255
quelle
Sie können weiterhin einfache Anführungszeichen wie dieses verwenden: sed -i '/ TEXT_TO_BE_REPLACED / c' "$ VARIABLE" '' / tmp / foo
Alistair McIntyre
4

Bei allen bisher gegebenen Antworten wird davon ausgegangen, dass Sie etwas über den zu ersetzenden Text wissen, was sinnvoll ist, da dies vom OP verlangt wurde. Ich gebe eine Antwort, die davon ausgeht, dass Sie nichts über den zu ersetzenden Text wissen und dass die Datei möglicherweise eine separate Zeile mit demselben oder einem ähnlichen Inhalt enthält, den Sie nicht ersetzen möchten. Außerdem gehe ich davon aus, dass Sie die Zeilennummer der zu ersetzenden Leitung kennen.

Die folgenden Beispiele zeigen das Entfernen oder Ändern von Text durch bestimmte Zeilennummern:

# replace line 17 with some replacement text and make changes in file (-i switch)
# the "-i" switch indicates that we want to change the file. Leave it out if you'd
#   just like to see the potential changes output to the terminal window.
# "17s" indicates that we're searching line 17
# ".*" indicates that we want to change the text of the entire line
# "REPLACEMENT-TEXT" is the new text to put on that line
# "PATH-TO-FILE" tells us what file to operate on
sed -i '17s/.*/REPLACEMENT-TEXT/' PATH-TO-FILE

# replace specific text on line 3
sed -i '3s/TEXT-TO-REPLACE/REPLACEMENT-TEXT/'
b_laoshi
quelle
3

zur Manipulation von Konfigurationsdateien

Ich habe diese Lösung gefunden, die von der Skensell-Antwort inspiriert ist

configLine [searchPattern] [replaceLine] [filePath]

es wird:

  • Erstellen Sie die Datei, falls nicht vorhanden
  • Ersetzen Sie die gesamte Zeile (alle Zeilen) in searchPattern übereinstimmt
  • Fügen Sie am Ende der Datei replaceLine hinzu, wenn das Muster nicht gefunden wurde

Funktion:

function configLine {
  local OLD_LINE_PATTERN=$1; shift
  local NEW_LINE=$1; shift
  local FILE=$1
  local NEW=$(echo "${NEW_LINE}" | sed 's/\//\\\//g')
  touch "${FILE}"
  sed -i '/'"${OLD_LINE_PATTERN}"'/{s/.*/'"${NEW}"'/;h};${x;/./{x;q100};x}' "${FILE}"
  if [[ $? -ne 100 ]] && [[ ${NEW_LINE} != '' ]]
  then
    echo "${NEW_LINE}" >> "${FILE}"
  fi
}

Die verrückte Magie des Exit-Status kommt von https://stackoverflow.com/a/12145797/1262663

Korn
quelle
2
bash-4.1$ new_db_host="DB_HOSTNAME=good replaced with 122.334.567.90"
bash-4.1$ 
bash-4.1$ sed -i "/DB_HOST/c $new_db_host" test4sed
vim test4sed
'
'
'
DB_HOSTNAME=good replaced with 122.334.567.90
'

es funktioniert gut

nkl
quelle
1

In meinem Makefile verwende ich Folgendes:

@sed -i '/.*Revision:.*/c\'"`svn info -R main.cpp | awk '/^Rev/'`"'' README.md

PS: NICHT Vergessen Sie , dass das -i tatsächlich den Text in der Datei ändert. Wenn sich also das als "Revision" definierte Muster ändert, ändern Sie auch das zu ersetzende Muster.

Beispielausgabe:

Abc-Projekt von John Doe

Revision: 1190

Wenn Sie also das Muster "Revision: 1190" festlegen, ist es offensichtlich nicht dasselbe, wie Sie sie als "Revision:" definiert haben ... nur ...

Martin Pfeffer
quelle
1
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

Die Datei find_replace enthält 2 Spalten, c1 mit passendem Muster, c2 mit Ersetzung. Die sed-Schleife ersetzt jede Zeile, die eines der Muster von Variable 1 enthält

sjordi
quelle
Nein, das ist in mehrfacher Hinsicht falsch. Führen Sie es sedeinmal mit einer Skriptdatei aus, die alle Ersetzungen enthält, die Sie ausführen möchten. Das sed -iwiederholte Ausführen derselben Datei ist ein schreckliches Antimuster.
Tripleee
0

Es ist so ähnlich wie oben ..

sed 's/[A-Za-z0-9]*TEXT_TO_BE_REPLACED.[A-Za-z0-9]*/This line is removed by the admin./'
Annapureddy Hari
quelle
3
Dass Änderungen FOO=TEXT_TO_BE_REPLACEDan FOO=This line ...nicht erfüllen so die Spezifikation nicht.
Jens
Ja. Wir müssen die gesamte Zeile durch "Diese Zeile wird vom Administrator entfernt" ersetzen. wenn wir den Schlüssel pattren 'TEXT_TO_BE_REPLACED' gefunden haben. Der obige Befehl ist zufriedenstellend. Korrigieren Sie mich, wenn mein Verständnis falsch ist. @Jens
Annapureddy Hari
@AnnapureddyHari Diese Antwort funktioniert nicht, wenn der Text vor oder nach der Suchzeichenfolge außer A-Za-z0-9 noch etwas enthält. Es schlägt fehl, wenn es ein Gleichheitszeichen gibt, wie Jens betonte. Der Teil "FOO =" bleibt erhalten; Sie haben nicht die gesamte Zeile ersetzt. Dieser Code ist kurzsichtig, was in der Datei enthalten sein könnte. Wenn Sie Platzhalter meinen, sollten Sie Platzhalter setzen, wie Thors Antwort zeigt.
msouth
0

Der folgende Befehl funktioniert für mich. Welches arbeitet mit Variablen

sed -i "/\<$E\>/c $D" "$B"
Ritesh Borkar
quelle
Meine neue Anforderung besteht jedoch darin, beim Ersetzen eine kommentierte Zeile (beginnend mit #) zu überspringen. Wenn wir die vollständige Zeile ersetzen, werden auch kommentierte Zeilen ersetzt, und Sie erhalten doppelte Eigenschaften. Wenn jemand eine Lösung dafür hat, lass es mich wissen.
Ritesh Borkar
-1

Ich benutze sehr oft Regex, um Daten aus Dateien zu extrahieren. Ich habe das nur verwendet, um das wörtliche Zitat \"durch //nichts zu ersetzen :-)

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
staM
quelle