it-swarm.com.de

So extrahieren Sie einen String nach einem Muster mit grep, regex oder perl

Ich habe eine Datei, die ungefähr so ​​aussieht:

<table name="content_analyzer" primary-key="id">
  <type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
  <type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
  <type="global" />
</table>

Ich muss etwas aus den Anführungszeichen entnehmen, die auf name= folgen, d. H. content_analyzer, content_analyzer2 und content_analyzer_items.

Ich mache dies auf einer Linux-Box, also ist eine Lösung mit sed, Perl, grep oder bash in Ordnung.

68
wrangler

Da Sie den Inhalt abgleichen müssen, ohne ihn in das Ergebnis aufzunehmen (muss Mit name=" übereinstimmen, er ist jedoch nicht Teil des gewünschten Ergebnisses), ist eine Form des Dies kann einfach mit den folgenden Tools durchgeführt werden:

Perl

Mit Perl können Sie die Option n verwenden, um Zeile für Zeile eine Schleife zu erstellen und den Inhalt einer einfangenden Gruppe zu drucken, wenn Folgendes zutrifft:

Perl -ne 'print "$1\n" if /name="(.*?)"/' filename

GNU grep

Wenn Sie über eine verbesserte Version von grep verfügen, z. B. GNU grep, haben Sie möglicherweise die Option -P für Mit dieser Option wird Perl-like-regex, Aktiviert, sodass Sie \K verwenden können, eine Abkürzung für lookbehind. Es wird die Übereinstimmungsposition zurückgesetzt, also ist alles, bevor es null ist, die Breite.

grep -Po 'name="\K.*?(?=")' filename

Die Option o sorgt dafür, dass grep nur den übereinstimmenden Text anstelle der ganzen Zeile

Vim - Texteditor

Eine andere Möglichkeit ist die direkte Verwendung eines Texteditors. Mit Vim besteht eine der verschiedenen Möglichkeiten, dies zu erreichen, darin, Zeilen ohne name= zu löschen und dann den Inhalt aus den resultierenden Zeilen zu extrahieren:

:v/name=/d
:%s/\v.*name\="([^"]+)".*/\1

Standard grep

Wenn Sie aus irgendeinem Grund keinen Zugriff auf diese Tools haben, könnte mit dem Standard-grep etwas Ähnliches erreicht werden. Ohne den Look Um ihn herum wird jedoch später eine Bereinigung erforderlich sein:

grep -o 'name="[^"]*"' filename

Ein Hinweis zum Speichern von Ergebnissen

In allen obigen Befehlen werden die Ergebnisse an stdout gesendet. Es ist wichtig, daran zu denken, dass Sie sie immer speichern können, indem Sie sie in eine .__-Datei leiten, indem Sie Folgendes hinzufügen:

> result

bis zum Ende des Befehls.

126
sidyll

Wenn Sie Perl verwenden, laden Sie ein Modul herunter, um das XML zu analysieren: XML ​​:: Simple , XML ​​:: Twig oder XML ​​:: LibXML . Das Rad nicht neu erfinden.

5
shawnhcorey

Der reguläre Ausdruck wäre:

.+name="([^"]+)"

Dann wäre die Gruppierung in der\1 

5
Matt Shaver

Ein HTML-Parser sollte zu diesem Zweck anstelle von regulären Ausdrücken verwendet werden. Ein Perl-Programm, das HTML::TreeBuilder verwendet:

Programm

#!/usr/bin/env Perl

use strict;
use warnings;

use HTML::TreeBuilder;

my $tree = HTML::TreeBuilder->new_from_file( \*DATA );
my @elements = $tree->look_down(
    sub { defined $_[0]->attr('name') }
);

for (@elements) {
    print $_->attr('name'), "\n";
}

__DATA__
<table name="content_analyzer" primary-key="id">
  <type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
  <type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
  <type="global" />
</table>

Ausgabe

content_analyzer
content_analyzer2
content_analyzer_items
4

Hier ist eine Lösung, die HTML tidy & xmlstarlet verwendet:

htmlstr='
<table name="content_analyzer" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
<type="global" />
</table>
'

echo "$htmlstr" | tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null |
sed '/type="global"/d' |
xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -n
2
mitma

das könnte es tun:

Perl -ne 'if(m/name="(.*?)"/){ print $1 . "\n"; }'
2
Benoit

Ups, der sed-Befehl muss natürlich vor dem ordentlichen Befehl stehen

echo "$htmlstr" | 
sed '/type="global"/d' |
tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null |
xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -n
1
mitma

Wenn die Struktur Ihrer XML-Datei (oder der Text im Allgemeinen) fest ist, verwenden Sie cut am einfachsten. Für Ihren speziellen Fall:

echo '<table name="content_analyzer" primary-key="id">
  <type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
  <type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
  <type="global" />
</table>' | grep name= | cut -f2 -d '"'
0
Carlos Lindado