![Auswählen eines Abschnitts einer Datei](https://rvso.com/image/164701/Ausw%C3%A4hlen%20eines%20Abschnitts%20einer%20Datei.png)
Ich habe eine Datei, die wie folgt formatiert ist:
title1
line
line
title2
line
line
line
title3
line
line
und ich möchte den Abschnitt darunter extrahieren title2
und den Einzug entfernen. Ich verwende derzeit Folgendes sed
(aber awk
oder ein Shell-Skript wäre in meinem Kontext geeignet, leider keine Sprachen wie perl
oder ):python
sed -n -e '/^title2$/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; s/^[ \t]*// ; p }'
aber das lässt am Ende eine logisch leere Zeile übrig (logisch, weil sie Leerzeichen oder Tabulatoren enthalten kann). Ich möchte sie loswerden. Beachten Sie, dass es in dem zu behaltenden Teil möglicherweise andere logisch leere Zeilen gibt (oder ein /^[ \t]*$/ d
hätte die Arbeit erledigt). Daher hätte ich gerne dieses Ergebnis:
line
line
line
Ich kann es mit einem zusätzlichen tun sed -e '$d'
, aber ich möchte wissen, ob es möglich ist, diesen zweiten Vorgang zu vermeiden.
Antwort1
Ich habe den Wartebereich genutzt und am Ende hatte ich
sed -ne '/^title2$/,/^[a-zA-Z]/ { /^title2$/ { n; h; b; } ; /^[a-zA-Z]/ d; H; x; s/[ \t]*//; P; s/.*\n//; x }'
das die von mir betreuten Fälle anscheinend korrekt behandelt.
Antwort2
- Wenn es sich um eine "reine" Zeile handelt (ohne Tabulator oder Weiß), löschen Sie diese ebenfalls mit
/^$/
für "logische" Blankonutzung
/^\s*$/
sed -n -e '/^title2:/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; /^$/ d ; s/^[ \t]*// ; p }'
Wo
/^$/
Startzeile und Zeilenende abgleichen/^\s*$/
Übereinstimmung mit Startzeile, null oder mehr Leerzeichen oder Tabulatoren, Zeilenende
Antwort3
sed -n '/title2/,/^\S/ { //b; /^\s*$/ { N; /\n\S/q; P; D }; s/^\s*//; p }'
Ich habe dies ursprünglich getan, um die Aufmerksamkeit von @Archemar zu erregen. Ich wäre Ihnen sehr dankbar, wenn SieBitteAntwort anmein Kommentar in diesem Beitragwann immer du Zeit hast. Auch wenn die Antwort "Ich weiß nicht" ist. DANKE.
Zumindest in meiner Bash-Shell funktioniert es ohne -e
. Ich bin nur neugierig, warum es überhaupt nötig ist. Und wenn\s
oder\S
nicht unterstützt wird, können Sie sie durch [ \t]
's bzw. [^ \t]
's ersetzen.
Aufschlüsselung für Leute, die genauso ahnungslos waren wie ich, als ich diese Frage zum ersten Mal sah:
-n
schaltet den automatischen Druck aus/title2/,/^\S/
ist ein Bereich,sed
in dem gesucht werden soll (von der Zeile des ersten Vorkommens der Zeichenfolge "title2
" bis zur nächsten Zeile, die mit einem Zeichen beginnt, das kein Leerzeichen ist [dhtitle3
]einschließlich){
bedeutet nur, die beigefügten Befehle auf den Bereich oder das Muster anzuwenden, das ich gerade angegeben habe//b
ermöglicht, dass die folgenden Befehle nicht auf den Anfang und das Ende des Bereichs angewendet werden.
Genauer gesagt, wenn Sie eine Übereinstimmung herstellentitle2
oder^\S
einfach zum Ende des Skripts (b
) verzweigen (die nächste Zeile in der Datei verarbeiten, falls noch welche übrig sind), weil inGNUsed
(BSDsagt ähnlich, bin mir nicht sicher, ob es eine andere Version davon gibtsed
)'//' wiederholt die letzte Übereinstimmung mit dem regulären Ausdruck
/^\s*$/
stimmt mit den „logisch leeren“ Zeilen im Bereich überein.{
N; /\n\S/q;
Wenn es sich also um eine „logisch leere“ Zeile handelt,N
wird die nächste Zeile zum Musterbereich hinzugefügt. Wenn es sich bei dieser nächsten Zeile jedoch um den nächsten Titel handelt, wird die Verarbeitung vollständig abgebrochen (q
), sodass weder die „logisch leere“ Zeile noch der nächste Titel gedruckt werden.P; D
Wenn die „logisch leere“ Zeileist nichtgefolgt vom nächsten Titel, dannNurdie "logisch leere" Zeile wird gedruckt(P
), und dannNurDie „logisch leere“ Zeile wird aus dem Musterbereich gelöscht, sodass die nächste Zeile, die durch Skript( ) zum Musterbereich hinzugefügt wurde,N
vom Anfang des Skripts an verarbeitet werden kann.D
}
s/^\s*//; p
entfernt die Leerzeichen und Tabulatoren am Zeilenanfang und druckt die formatierte Zeile
}
@Archemar bitteHELFEN