Zeile nach dem n-ten Auftreten einer Übereinstimmung drucken

8

Ich möchte die Zeile 4598 in der folgenden Datei anzeigen. Eigentlich möchte ich die Zeile NACH dem n-ten Auftreten einer Übereinstimmung anzeigen. In diesem Fall ist die Zeile nach dem 3. Auftreten von <Car>. Wie gehe ich vor?

<Car>
10456
</Car>
<Car>
70192
</Car>
<Car>
4598
</Car>
DJ180
quelle
1
Während es möglich sein könnte , zu erreichen , was Sie wollen , mit sed, awkoder sogar grep, ist es ratsam , die Verwendung eines XML - Parser zu machen.
devnull
XML wurde nur für das Beispiel verwendet, Text kann ein beliebiges Format haben
DJ180

Antworten:

10
awk -v n=3 '/<Car>/ && !--n {getline; print; exit}'

Oder:

awk '/<Car>/ && ++n == 3 {getline; print; exit}'

So übergeben Sie das Suchmuster als Variable:

var='<car>'
PATTERN="$var" awk -v n=3 '
  $0 ~ ENVIRON["PATTERN"] && ++n == 3 {getline; print; exit}'

Hier werden Backslash-Escape-Sequenzen ENVIRONanstelle von -vas -vverwendet, und Backslashes werden häufig in regulären Ausdrücken gefunden (müssten also verdoppelt werden -v).

Mit GNU awk4.2 oder höher können Sie Variablen als stark typisierte reguläre Ausdrücke zuweisen . Solange der POSIX-Modus nicht aktiviert ist (z. B. über die $POSIXLY_CORRECTUmgebungsvariable), können Sie Folgendes tun:

# GNU awk 4.2 or above only, when not in POSIX mode
gawk -v n=3 -v pattern="@/$var/" '
  $0 ~ pattern && ++n == 3 {getline; print; exit}'
Stéphane Chazelas
quelle
Wie man das Suchmuster auch als Variable im obigen Befehl
übergibt
@WanderingMind, siehe Bearbeiten.
Stéphane Chazelas
4

Hier ist ein Perl:

perl -ne 'print && exit if $c==3; $c++ if /<Car>/;' file 

Mit GNU grepkönnen Sie die Ausgabe auch wie folgt analysieren:

grep -A 1 -m 3 '<Car>' file | tail -n 1

Von man grep:

-A NUM, --after-context=NUM
          Print NUM lines of trailing context after matching lines.  
          Places a line containing a group separator (--) between 
          contiguous  groups  of  matches.          
-m NUM, --max-count=NUM
          Stop reading a file after NUM matching lines.  
terdon
quelle
3

Mit können GNU awkSie tun:

gawk -v RS='</Car>' 'NR==3 && $0=$2' inputFile
jaypal singh
quelle
1

Hier ist ein anderer Weg mit sed:

sed -n '/<Car>/{x;/.\{2\}/{x;$!{n;p};q};s/.*/&./;x}' infile

Dies verwendet den Haltebereich zum Zählen.
Jedes Mal , trifft es auf eine Leitungsanpassung <Car>ë xÄnderungen Puffer und überprüft , ob es genau ist N-1 Vorkommen eines Zeichens in dem Haltepuffer. Wenn die Prüfung erfolgreich ist, xändert sie sich erneut, und wenn sie nicht in der letzten Zeile steht, zieht sie die next-Zeile ein und pdruckt den Musterbereich dann qaus. Andernfalls wird dem Haltebereich nur ein weiteres .Zeichen hinzugefügt, und e xwechselt zurück.

don_crissti
quelle
0

Hier ist eine einfache Befehlszeilenlösung.

grep -F -A1 '<Car>' filename | grep -E -v '<Car>|--' | tail -n +3 |head -n +1

Wenn Sie den Wert von +3 danach ändern tail, können Sie eine beliebige n-te Zeile angeben.

bsd
quelle
Sie sind sich nicht sicher, warum Sie die Tags, sed, awk usw. hinzugefügt haben. Wenn Sie eine Lösung mit einer bestimmten App oder einem bestimmten Dienstprogramm wünschen, sollten Sie dies in Frage oder Titel angeben.
BSD