LINUX.ORG.RU

Сравнить два больших текстовых файла

 


0

2

Всем привет. Есть достаточно простая задача для знающих людей. И поскольку я сам программировать не умею, то прошу помощи.

Есть текстовые файлы 1.log (100KB) и a.log b.log c.log (по 600МБ каждый) итд

1.log это столбец из цифр (пример http://78.47.220.147/kea/work/1.log)

a.log это логи в формате:

foo rlist <29092 28550 23112 22112 12717 2581 32229 32377 32846 10771 17850 19984 33370 28010 27560 16476 16478 19134 >bar

(пример http://78.47.220.147/kea/work/a.log)

Мне нужно две вещи:

1) Найти все значения из 1.log, которых нет внутри rlist в a.log b.log c.log итд

2) Посчитать сколько повторений во всех файлах по каждому значению в rlist

Для первой части я написал строчку на баше с sed, sort, uniq и diff, но она работает только для малого количества данных (мои файлы обрабатываются невыносимо долго)

За помощь буду готов отблагодарить.


1) Найти все значения из 1.log, которых нет внутри rlist в a.log b.log c.log итд

Вот на скорую руку:

#!/usr/bin/perl

use strict;
use warnings;

my (@A, @B);

open LOGA, "<", "a.log" or die;
while (<LOGA>) {
	push @A, split(/\s/, $1) if /rlist\s*<(.+)>/;
}
close LOGA;

open LOGB, "<", "1.log" or die;
while (<LOGB>) {
	push @B, $1 if /(\d+)/;
}
close LOGB;

my %seen;
@seen{@A} = ();
delete @seen{@B};
my @aonly = keys %seen;

print join(" ", @aonly) . "\n";

SyntaxError
()
Ответ на: комментарий от SyntaxError

Для отсортированного вывода замени последнюю строчку на

print join(" ", sort @aonly) . "\n";

SyntaxError
()

2) Посчитать сколько повторений во всех файлах по каждому значению в rlist

Если я правильно понял то проверь это:

#!/usr/bin/perl 

use strict;
use warnings;

my @A;

open LOGA, "<", "a.log" or die;
while (<LOGA>) {
	push @A, split(/\s/, $1) if /rlist\s*<(.+)>/;
}
close LOGA;

my %seen = ();
map {$seen{$_}++} @A;

foreach my $item (sort keys %seen) {
	print "$item = $seen{$item}\n";
}

SyntaxError
()
Ответ на: комментарий от SyntaxError

Ну и сахар напоследок. Для сортировки в числовом порядке, а не в символьном допиши после sort такой код:

{$a <=> $b}

SyntaxError
()
Ответ на: комментарий от anonymous

Уговорил. Полная версия скрипта для второй задачи. На вход принимает список файлов-логов:

#!/usr/bin/perl 

use strict;
use warnings;

my @A;
my %seen = ();

foreach my $file_name (@ARGV){
	open LOG, "<", $file_name or next;
	while (<LOG>) {
		map {$seen{$_}++} split(/\s/, $1) if /rlist\s*<(.+)>/;
	}
	close LOG;
}

foreach my $item (sort{$a <=> $b} keys %seen) {
	print "$item = $seen{$item}\n";
}

Для первой задачи аналогично избавляемся от массива.

SyntaxError
()

Упоротое решение

cat 1.log | sed '/^\s*$/d' | sed 's/^\s*//' | sed 's/\([0-9]\+\)/\1 \1/g' |  xargs -n 2 printf  "printf '%s ' && grep 'rlist\s*<.*%s.*>' a.log | wc -l\n" | sh
anonymous
()

Для первой части я написал строчку на баше с sed, sort, uniq и diff, но она работает только для малого количества данных (мои файлы обрабатываются невыносимо долго)

Есть очень полезная утилита - combine. Она работает только со строками, так что всё равно придётся приводить данные в двух файлов к одному виду. Но по идее она должна работать быстрее diff'а.

Deleted
()
Ответ на: комментарий от SyntaxError

Так же полная версия скрипта для первой задачи. На вход принимает список файлов-логов:

#!/usr/bin/perl

use strict;
use warnings;

my (@B, %aonly);
my %seen = ();

open LOGB, "<", "1.log" or die;
while (<LOGB>) {
		push @B, $1 if /(\d+)/;
}
close LOGB;
@seen{@B} = ();

foreach my $file_name (@ARGV){
	open LOGA, "<", $file_name or next;
	while (<LOGA>) {
		my @rlist_row = split(/\s/, $1) if /rlist\s*<(.+)>/;
		map {$aonly{$_}++ unless exists $seen{$_}} @rlist_row;
	}
close LOGA;
}

print join(" ", sort {$a <=> $b} keys %aonly) . "\n";

SyntaxError
()
Ответ на: комментарий от SyntaxError

Спасибо! Первый скрипт работает немного не так. Он ищет уникальные значения в логах, а не в полном списке rlist'a.

[root@invoice151 test]# cat 1.log
1
2
3
4
5
6
7
8
9
10
776
[root@invoice151 test]# cat a.log
blah blahadfafd rlist <1 > dsafasdfa
blah blahadfafd rlist <1 2 44 3 >adfsdf
blah blahadfafd rlist <1 33 32 2 3 >321faf
blah blahadfafd rlist <1 45 6 >asdfasdfasdf
blah blahadfafd rlist <1 8 >asdfasd
blah blahadfafd rlist <1 9 >ewqrqw
blah blahadfafd rlist <1 10 >asdfe2f1
[root@invoice151 test]# ./pipo2.pl
32 33 45 44

а должен находить - 4 5 7 776

ky4k0b
() автор топика
Ответ на: комментарий от SyntaxError

Вторая часть работает как надо. Напиши номер телефона на ky4k0b @ gmail.com или через альфаклик денег перекину за помощь :)

ky4k0b
() автор топика
Ответ на: комментарий от anonymous

это ты о чём?
vim легко открывает гиговые файлы

q11q11 ★★★★★
()

на всякий случай вот решение первой задачи на питоне

#!/usr/bin/python

import re
import sys

numbers = set()
r = re.compile(r"(\d+)")
with open("1.log", "r") as f:
	for l in f:
		m = r.match(l)
		if m:
			numbers.add(m.group(0))

r_rlist = re.compile(r".+rlist\s*<(.+)>")
r_spl = re.compile(r'\s')
for fn in sys.argv[1:]:
	with open(fn, "r") as f:
		for l in f:
			m = r_rlist.match(l)
			if m:
				lst = r_spl.split(m.group(1).strip(' '))
				for n in lst:
					numbers.discard(n)

print " ".join(sorted(numbers, key=lambda x: int(x)))
ky4k0b
() автор топика
Ответ на: комментарий от ky4k0b

а должен находить - 4 5 7 776

Понял. Вот в копилку на перле.

#!/usr/bin/perl

use strict;
use warnings;

my (%A, %B, %bonly);
my %seen = ();

foreach my $file_name (@ARGV){
	open LOGA, "<", $file_name or next;
	while (<LOGA>) {
		map {$A{$_}++} split(/\s/, $1) if /rlist\s*<(.+)>/;
	}
close LOGA;
}

open LOGB, "<", "1.log" or die;
while (<LOGB>) {
	$bonly{$1}++ if /(\d+)/ and !exists $A{$1};
}
close LOGB;


print join(" ", sort {$a <=> $b} keys %bonly) . "\n";

денег перекину за помощь :)

мне хватит и спасибо :)

SyntaxError
()
Ответ на: комментарий от SyntaxError

В целях экономии памяти лучше написать так:

#!/usr/bin/perl

use strict;
use warnings;

my (%A, %B);

open LOGB, "<", "1.log" or die;
while (<LOGB>) {
	$A{$1}++ if /(\d+)/;
}
close LOGB;

foreach my $file_name (@ARGV){
	open LOGA, "<", $file_name or next;
	while (<LOGA>) {
		map {delete $A{$_}} split(/\s/, $1) if /rlist\s*<(.+)>/;
	}
close LOGA;
}

print join(" ", sort {$a <=> $b} keys %A) . "\n";

SyntaxError
()
Ответ на: комментарий от SyntaxError

тогда спасибо большое! задачу можно считать решенной

ky4k0b
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.