Zliczanie ile razy każdy adres IP pojawia się w pliku dziennika

9

Mam plik w następującym formacie:

$ cat file.txt

27.33.65.2
27.33.65.2
58.161.137.7
121.50.198.5
184.173.187.1
184.173.187.1
184.173.187.1

Jaki jest najlepszy sposób na parsowanie pliku file.txtdo formatu takiego jak:

27.33.65.2: 2
58.161.137.7: 1
121.50.198.5: 1
184.173.187.1: 3

Innymi słowy, chcę przejrzeć plik i policzyć, ile razy pojawia się każdy adres IP. Już go uruchomiłem, sortwięc wszystkie adresy IP są w porządku i bezpośrednio po sobie.

James Spittal
źródło
Ja osobiście importowałbym ten rodzaj pliku do poręcznego pobliskiego DB (tworząc tabelę tymczasową w dowolnej instancji postgres, którą mam w pobliżu), a następnie wykonuję szybką akcję SQL i eksportuję z powrotem do pliku tekstowego.
oakad

Odpowiedzi:

23

Szukasz uniq -c

Jeśli wynik tego nie przypadnie Ci do gustu, możesz go łatwo przeanalizować i sformatować.

Na przykład:

$ uniq -c logfile.txt | awk '{print $2": "$1}'
27.33.65.2: 2
58.161.137.7: 1
121.50.198.5: 1
184.173.187.1: 3
Glenn Jackman
źródło
Łączenie uniqi awknie wydaje się być dla mnie świetnym podejściem ...
Hauke ​​Laging
3
Ponieważ uniqdziała tylko na posortowane dane wejściowe (pasuje do sąsiednich pasujących linii, a nie do żadnych linii z pliku).
oakad
1
Musisz posortować wyniki przed potokowaniem ich do uniq. Jeśli przeczytasz oryginalne Q, OP stwierdza, że ​​już posortował wyniki za pomocą sort!
slm
2
@HaukeLaging - Doceniam to, co mówisz, ale w ten sam sposób, w jaki większość użytkowników komputerów nigdy nie zapuści się poza OSX i Windows, a ponadto większość użytkowników Uniksa nie zapuści się więcej niż za pomocą wyznaczonych narzędzi do określonych zadań. Korzystanie z AWK nie jest dla osób o słabym sercu, spójrz na to, co musiałeś zrobić, aby wykonać to podstawowe zadanie przy użyciu AWK, a nie na to, czego wymagało rozwiązanie Glenna. Myślę, że uczciwie mogę powiedzieć, że jego jest prostszym rozwiązaniem do zrozumienia mentalnego, chociaż twoje jest prawdopodobnie bardziej wydajne. BTW, zrobiłem UV oba, ponieważ oba są poprawne!
slm
1
@HaukeLaging - Tak, dokładnie. Gdy kręcisz się po stronie, nasze obowiązki nieznacznie się zmieniają, IMO. Jesteśmy odpowiedzialni za tworzenie kompleksowych A'erów i patrzenie na A'ery, które zapewniamy jako momenty nauczania OP i każdemu przyszłemu odwiedzającemu, ponownie IMO. Ale jest to osobisty wybór, więc jeśli masz tylko kilka minut do stracenia, zawsze mile widziane jest zapewnienie A w dowolnej formie.
slm
6

uniqwydaje się rzeczywiście najsprytniejszym rozwiązaniem. Awk sposób:

awk '{ip_count[$0]++}; '\
'END {for (ip in ip_count) printf "%15s: %d\n",ip,ip_count[ip];}' file
Hauke ​​Laging
źródło
+1. Jeśli kolejność danych wyjściowych jest ważna dla PO, odpowiedź ta nie daje żadnych gwarancji: iteracja po kluczach tablicy asocjacyjnej nie ma właściwej kolejności.
glenn jackman
@glennjackman Ale dodawanie sortdo mojej odpowiedzi jest jeszcze szybsze, ponieważ trzeba posortować mniej elementów. ;-)
Hauke ​​Laging
o tak? O TAK?!? ;) dane wejściowe są już posortowane. Ta odpowiedź na awk przetasowuje je, więc wciąż jest więcej pracy. Nie! ;)
glenn jackman
0

plik sortowania Firest, a następnie licznik unic -c

sort filename | uniq -c

Aeyd Moeyd
źródło
1
Plik jest już posortowany (według użytkownika w pytaniu) i uniq -cdziałałby, ale zapewniałby wyjście w niewłaściwym formacie. Dlatego przyjęta odpowiedź nie używa, sorta zamiast tego ponownie formatuje wyjście uniq -c.
Kusalananda
Dzięki @Aeyd. Szukałem tego polecenia. Pomaga
11392987,
0

Chciałbym użyć Pythona. Każdy system Linux ma obecnie zainstalowany Python2.

Dodaj każdy adres IP do słownika (tablicy asocjacyjnej) jako pary klucz = wartość, tj. {"12.34.56.78": 1, "87.76.43.21": 3}.

„Weryfikujesz” adres IP jako klucz i zwiększasz wartość o 1. Jeśli użyjesz defaultdict („ip”), jeśli klucz nie istnieje, zostanie utworzony z wartością domyślną 0. Jeśli klucz istnieje już defaultdict nic nie robi. Wartość jest zwiększana w następnym wierszu.

#!/usr/bin/python2

infile = open("file.txt","r")
iplist = {}  # create an empty dict

for line in infile:
    line = line.strip()   # remove newline.
    if line: # if not a blank line.
        iplist.setdefault(line, 0) # check for ip and add with default value of 0
        iplist[line] += 1 # increment

outfile = open("out.txt","w") #open output file

for key in iplist.keys():
    line = "%-15s = %s" % (key, iplist[key])
    print line   # print uf desired.
    outfile.write(line + "\n")

plik wyjściowy:

cat out.txt                                                          
27.33.65.2      = 2
58.161.137.7    = 1
121.50.198.5    = 1
184.173.187.1   = 3

Wiem, że szukałeś rozwiązania z linii poleceń, ale jak widać jest to elegancko sformatowany wyświetlacz, który zajął tylko kilkanaście linii. Python jest doskonałym narzędziem do administracji.

Mike Childers
źródło