sed - Kommentieren einer Zeile, die mit einer bestimmten Zeichenfolge übereinstimmt UND die noch nicht auskommentiert ist

73

Ich habe die folgende Testdatei

AAA
BBB
CCC

Mit dem folgenden sed kann ich die BBB- Zeile auskommentieren .

# sed -e '/BBB/s/^/#/g' -i file

Ich möchte die Zeile nur auskommentieren, wenn sie am Anfang noch kein # hat.

# sed -e '/^#/! /BBB/s/^/#/g' file

sed: -e expression #1, char 7: unknown command: `/'

Irgendwelche Ideen, wie ich das erreichen kann?

Jean-Francois Chevrette
quelle

Antworten:

97

Angenommen, Sie haben keine Zeilen mit mehreren #s, würde dies funktionieren:

sed -e '/BBB/ s/^#*/#/' -i file

Hinweis: Sie benötigen / g nicht, da Sie höchstens eine Ersetzung pro Zeile durchführen.

Aragaer
quelle
2
Dadurch wird die übereinstimmende Zeile immer so bearbeitet, dass sie mit einem einzelnen # beginnt. Wenn es also mit drei #Sekunden nach diesem Befehl begann, wird es "bereinigt", um nur mit einem zu beginnen #. Um dieses Problem zu beheben, wenn es ein Problem ist, ändern Sie einfach das passende Teil entsprechend (z. B. sed -e '/^BBB/...)
Steven Lu
3
sed '/^#BBB/'was meinen Sie. Aber wenn BBB irgendwo in der Mitte ist, wird es nicht funktionieren. Es gibt eine Option zum Schreiben, sed '/^#/! {/BBB/ s/^/#/}'die viel besser funktioniert, aber meine anfängliche Lösung ist viel einfacher, solange Sie die Einschränkung kennen.
Aragaer
Wie kann ich dem entkommen, wenn wir oben im Java-Programm verwenden?
Krishna Pandey
So : sed -e '/BBB/ s|^(//)*|//|' -i file. Beachten Sie, dass es nur für einzelne artige Kommentare funktioniert, geht davon aus, dass der Kommentar beginnt am Anfang der Zeile und mehrere ersetzen Paare von //mit einem einzigen //.
Aragaer
Ist es möglich, BBB in eine Eingabevariable einzufügen?
Fuseteam
9

Ich finde, dass diese Lösung am besten funktioniert.

sed -i '/^[^#]/ s/\(^.*BBB.*$\)/#\ \1/' file

Es spielt keine Rolle, wie viele "#" Symbole es gibt, es wird niemals ein weiteres hinzugefügt. Wenn das gesuchte Muster kein "#" enthält, wird es am Zeilenanfang und ein nachfolgendes Leerzeichen hinzugefügt.

Wenn Sie keinen nachgestellten Leerzeichen möchten

sed -i '/^[^#]/ s/\(^.*BBB.*$\)/#\1/' file
Bobbert Waitforit Hurny
quelle
Dies ist sehr nützlich für die Musterübereinstimmung. Vielen Dank
Chaminda Bandara
1
Möglicherweise möchten Sie "!" mit "^", aber ansonsten ist dies eine bessere Lösung als die offizielle Antwort
o
8

Eine andere Lösung mit dem &Sonderzeichen, das auf den gesamten übereinstimmenden Teil des Musterraums verweist. Es ist ein bisschen einfacher / sauberer als das Erfassen und Referenzieren einer regulären Ausdrucksgruppe.

sed -i 's/^[^#]*BBB/#&/' file
Agostonbarna
quelle
1

sed -i '/![^#]/ s/\(^.*BBB.*$\)/#\ \1/' file

Dies funktioniert bei mir mit dem Schlüsselwort nicht *.sudo , überhaupt keine Kommentare ...

Nur die folgende Syntax funktioniert: sed -e '/sudo/ s/^#*/#/' file

Rechnung
quelle
1

Angenommen, die BBB steht am Anfang einer Zeile, habe ich einen noch einfacheren Ausdruck verwendet:

sed -e '/^BBB/s/^/#/' -i file

Noch eine Anmerkung für die Zukunft mir. Übersehen Sie nicht die -i. Weil das nicht funktioniert : sed -e "..." same_file > same_file.

RayLuo
quelle
0

Tatsächlich benötigen Sie das Ausrufezeichen (!) Nicht, da das Caret-Symbol bereits alles negiert, was sich in den eckigen Klammern befindet, und alle Hash-Symbole bei Ihrer Suche ignoriert. Dieses Beispiel hat bei mir funktioniert:

sed -i '/[^#]/ s/\(^.*BBB.*$\)/#\ \1/' file

Dwayne Mcnab
quelle
0

Ich würde in der Regel liefern sedmit -i.bakBackup der Datei , bevor Sie Änderungen an der Originalkopie:

sed -i.bak '/BBB/ s/^#*/#/' file

Auf diese Weise habe ich beides fileund file.bakkann mich entscheiden, es file.bakerst zu löschen , wenn ich mir sicher bin.

Abolfazl Shahbazi
quelle