web-dev-qa-db-de.com

Wie extrahieren Sie IP-Adressen aus Dateien mit Regex in einer Linux-Shell?

Wie extrahiere ich einen Textteil durch Regex in Linux Shell? Nehmen wir an, ich habe eine Datei, in der sich in jeder Zeile eine IP-Adresse befindet, jedoch an einer anderen Stelle. Was ist der einfachste Weg, diese IP-Adressen mit üblichen Unix-Befehlszeilenprogrammen zu extrahieren?

56

Sie könnten grep verwenden, um sie herauszuziehen.

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' file.txt
112
brien

Die meisten Beispiele hier stimmen mit 999.999.999.999 überein, was technisch keine gültige IP-Adresse ist.

Die folgenden Angaben beziehen sich nur auf gültige IP-Adressen (einschließlich Netzwerk- und Broadcast-Adressen).

grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' file.txt

Lassen Sie das -o weg, wenn Sie die gesamte übereinstimmende Zeile sehen möchten.

40
Sarel Botha

Normalerweise beginne ich mit grep, um den Regex richtig zu machen.

# [multiple failed attempts here]
grep    '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*'                 file  # good?
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' file  # good enough

Dann würde ich versuchen, es in sed umzuwandeln, um den Rest der Zeile herauszufiltern. (Nach dem Lesen dieses Threads werden Sie und ich das nicht mehr tun: Stattdessen verwenden wir grep -o.)

sed -ne 's/.*\([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\).*/\1/p  # FAIL

In diesem Fall ärgere ich mich sed normalerweise, weil ich nicht die gleichen Regexen benutzt wie andere. Also gehe ich zu Perl.

$ Perl -nle '/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ and print $&'

Perl ist auf jeden Fall gut zu wissen. Wenn Sie ein kleines bisschen CPAN installiert haben, können Sie es sogar kostengünstiger machen:

$ Perl -MRegexp::Common=net -nE '/$RE{net}{IPV4}/ and say $&' file(s)
11
JB.

Dies funktioniert gut für mich in Zugriffsprotokollen.

cat access_log | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}'

Brechen wir es Stück für Stück auf.

  • [0-9]{1,3} bedeutet ein bis drei Vorkommen des in [] genannten Bereichs. In diesem Fall ist es 0-9. es passt also zu Mustern wie 10 oder 183.

  • Gefolgt von einem '.'. Wir müssen dem als '.' ist ein Meta-Charakter und hat eine besondere Bedeutung für die Shell.

Wir sind jetzt also bei Mustern wie '123'. '12. ' usw.

  • Dieses Muster wiederholt sich dreimal (mit '.'). Also schließen wir es in Klammern ein .([0-9]{1,3}\.){3}

  • Und zum Schluss wiederholt sich das Muster, diesmal jedoch ohne das ".". Deshalb haben wir es im 3. Schritt getrennt aufbewahrt. [0-9]{1,3}

Wenn sich die ips wie in meinem Fall am Anfang jeder Zeile befinden, verwenden Sie:

egrep -o '^([0-9]{1,3}\.){3}[0-9]{1,3}'

dabei ist '^' ein Anker, der am Anfang einer Zeile eine Suche angibt.

10
Sankalp

Ich habe ein kleines script geschrieben, um meine Protokolldateien besser zu sehen, es ist nichts Besonderes, kann aber vielen Leuten helfen, die Perl lernen. Es führt DNS-Suchvorgänge für die IP-Adressen durch, nachdem diese extrahiert wurden. 

3
James

Ich schrieb einen informativen Blogartikel zu diesem Thema: Gewusst wie: Extrahieren von IPv4- und IPv6-IP-Adressen aus Nur-Text mit Regex .

In diesem Artikel finden Sie eine detaillierte Anleitung zu den am häufigsten verwendeten unterschiedlichen Mustern für IPs, die häufig extrahiert und mithilfe von regulären Ausdrücken aus normalem Text isoliert werden müssen.
Dieses Handbuch basiert auf CodVerters IP Extractor Quellcode-Tool für die Extraktion und Erkennung von IP-Adressen, wenn dies erforderlich ist .

Wenn Sie die IPv4-Adresse validieren und erfassen möchten, kann dieses Muster die Aufgabe erfüllen:

\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b

oder zur Validierung und Erfassung der IPv4-Adresse mit Prefix ("Schrägstrichnotation"):

\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?/[0-9]{1,2})\b

oder zur Erfassung der Subnetzmaske oder der Platzhaltermaske:

(255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)

oder, um Subnetzmaskenadressen herauszufiltern, machen Sie dies mit Regex negativem Lookahead :

\b((?!(255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)))(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b

Für die Validierung von IPv6 können Sie den Artikel-Link aufrufen, den ich oben in dieser Antwort hinzugefügt habe.
Hier ist ein Beispiel für die Erfassung aller gängigen Muster (aus dem CodVerter-Hilfethema IP Extractor):

 enter image description here

Wenn Sie möchten, können Sie den IPv4-Regex hier testen.

2
jonathana

grep -E -o "([0-9] {1,3} [.]) {3} [0-9] {1,3}"

2
shaa0601

Sie können einen von mir erstellten Shell-Helfer verwenden: https://github.com/philpraxis/ipextract

haben sie hier der Bequemlichkeit halber beigefügt:

#!/bin/sh
ipextract () 
{ 
egrep --only-matching -E  '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' 
}

ipextractnet ()
{ 
egrep --only-matching -E  '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[[:digit:]]+' 
}

ipextracttcp ()
{ 
egrep --only-matching -E  '[[:digit:]]+/tcp' 
}

ipextractudp ()
{ 
egrep --only-matching -E  '[[:digit:]]+/udp' 
}

ipextractsctp ()
{ 
egrep --only-matching -E  '[[:digit:]]+/sctp' 
}

ipextractfqdn ()
{ 
egrep --only-matching -E  '[a-zA-Z0-9]+[a-zA-Z0-9\-\.]*\.[a-zA-Z]{2,}' 
}

Laden Sie es (wenn es in der ipextract-Datei gespeichert ist) von Shell:

$. ipextract

Benutze sie:

$ ipextract < /etc/hosts
127.0.0.1
255.255.255.255
$

Für ein Beispiel eines echten Einsatzes:

ipextractfqdn < /var/log/snort/alert | sort -u
dmesg | ipextractudp
2
Phil L.

Sie können sed verwenden. Aber wenn Sie Perl kennen, könnte das einfacher und auf lange Sicht nützlicher sein:

Perl -n '/(\d+\.\d+\.\d+\.\d+)/ && print "$1\n"' < file
1
Avi

Sie könnten auch awk verwenden. So etwas wie ...

awk '{i = 1; if (NF> 0) do {if ($ i ~/regexp /) print $ i; i ++;} while (i <= NF);} 'Datei

- kann gereinigt werden. Nur eine schnelle und schmutzige Antwort, um im Grunde zu zeigen, wie man es mit awk macht

0
Allen Ratcliff

Ich habe alle Antworten ausprobiert, aber alle hatten ein oder viele Probleme, die ich einige auflistete.

  1. Einige erkannten 123.456.789.111 als gültige IP-Adresse 
  2. Einige erkennen 127.0.00.1 nicht als gültige IP-Adresse 
  3. Einige erkennen keine IP, die mit Null beginnen, wie 08.8.8.8

Also poste ich hier einen Regex, der unter allen oben genannten Bedingungen funktioniert. 

Hinweis: Ich habe mehr als 2 Millionen IP-Adressen problemlos mit folgendem Regex extrahiert.

(?:(?:1\d\d|2[0-5][0-5]|2[0-4]\d|0?[1-9]\d|0?0?\d)\.){3}(?:1\d\d|2[0-5][0-5]|2[0-4]\d|0?[1-9]\d|0?0?\d)
0
Mohsen Sarkar

Alle vorherigen Antworten haben ein oder mehrere Probleme. Die akzeptierte Antwort erlaubt IP-Nummern wie 999.999.999.999. Für die derzeit am zweithöchsten bewertete Antwort ist die Angabe von 0 wie 127.000.000.001 oder 008.008.008.008 anstelle von 127.0.0.1 oder 8.8.8.8 erforderlich. Apama hat es fast richtig, aber für diesen Ausdruck ist es erforderlich, dass die IP-Nummer das einzige in der Zeile ist. Es darf kein Leerzeichen vor- oder nachgestellt werden, und es kann auch keine IP aus der Mitte einer Zeile ausgewählt werden.

Ich denke, der korrekte Regex ist auf http://www.regextester.com/22 zu finden.

Wenn Sie also alle IP-Adressen aus einer Datei extrahieren möchten, verwenden Sie:

grep -Eo "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])" file.txt

Wenn Sie keine Duplikate wünschen, verwenden Sie:

grep -Eo "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])" file.txt | sort | uniq

Bitte kommentieren Sie, ob es noch Probleme in dieser Regex gibt. Es ist leicht, viele falsche Regex für dieses Problem zu finden. Ich hoffe, dieser hat keine echten Probleme.

0
anneb

Jeder hier verwendet sehr lange reguläre Ausdrücke, aber wenn Sie die Regex von POSIX verstehen, können Sie einen kleinen grep-Befehl wie diesen zum Drucken von IP-Adressen verwenden.

grep -Eo "(([0-9]{1,3})\.){3}([0-9]{1,3})"

(Randnotiz) Ungültige IPs werden nicht ignoriert, aber es ist sehr einfach.

0
Yokai

Für diejenigen, die eine fertige Lösung zum Abrufen von IP-Adressen aus dem Apache-Protokoll und zum Auflisten der Häufigkeit, mit der die IP-Adresse die Website besucht hat, wünschen, verwenden Sie diese Zeile:

grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' error.log | sort | uniq -c | sort -nr > occurences.txt

Schöne Methode, um Hacker zu verbieten. Als nächstes können Sie:

  1. Löschen Sie Zeilen mit weniger als 20 Besuchen
  2. Wenn Sie RegExp verwenden, schneiden Sie bis zum einzelnen Speicherplatz, sodass Sie nur IP-Adressen haben
  3. Verwenden Sie reguläre Ausdrücke, um 1-3 letzte Nummern von IP-Adressen zu schneiden, sodass Sie nur Netzwerkadressen haben
  4. Fügen Sie deny from und ein Leerzeichen am Anfang jeder Zeile hinzu
  5. Legen Sie die Ergebnisdatei als .htaccess ab
0
pbies

Ich würde Perl vorschlagen. (\ d +.\d +.\d +.\d +) sollte den Trick wahrscheinlich tun. 

EDIT: Um es eher wie ein komplettes Programm zu machen, können Sie Folgendes tun (nicht getestet): 

#!/usr/bin/Perl -w
use strict;

while (<>) {
    if (/(\d+\.\d+\.\d+\.\d+)/) {
        print "$1\n";
    }
}

Dies behandelt eine IP pro Leitung. Wenn Sie mehr als eine IP-Adresse pro Leitung haben, müssen Sie die Option/g verwenden. man perlretut gibt ein detailliertes Tutorial zu regulären Ausdrücken. 

0
PolyThinker