Подтвердить что ты не робот

Найти содержимое одного файла из другого файла в UNIX

У меня есть 2 файла. Первый файл содержит список идентификаторов строк кортежей таблицы в базе данных. Второй файл содержит SQL-запросы с этим идентификатором строки в предложении "where" запроса.

Например:

Файл 1

1610657303
1610658464
1610659169
1610668135
1610668350
1610670407
1610671066

Файл 2

update TABLE_X set ATTRIBUTE_A=87 where ri=1610668350;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672154;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610668135;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672153;

Мне нужно прочитать файл 1 и выполнить поиск в файле 2 для всех команд SQL, которые соответствуют идентификатору строки из файла 1, и сбрасывать эти SQL-запросы в третьем файле.

Файл 1 имеет 1 000 000 записей, а файл 2 содержит 10 записей в файле 1, то есть 1,000000.

Я использовал grep -f File_1 File_2 > File_3. Но это очень медленно, и скорость составляет 1000 записей в час.

Есть ли более быстрый способ сделать это?

4b9b3361

Ответ 1

Один из способов: awk:

awk -v FS="[ =]" 'NR==FNR{rows[$1]++;next}(substr($NF,1,length($NF)-1) in rows)' File1 File2

Это должно быть довольно быстро. На моей машине потребовалось менее 2 секунд, чтобы создать поиск по 1 миллиону записей и сравнить его с 3 миллионами строк.

Характеристики машины:

Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz (8 cores)
98 GB RAM

Ответ 2

Вам не нужны регулярные выражения, поэтому grep -F -f file1 file2

Ответ 3

Возможно, я что-то пропустил, но не хватит ли просто повторять идентификаторы в file1 и для каждого ID, grep file2 и сохранять совпадения в третьем файле? То есть.

 for ID in `cat file1`; do grep $ID file2; done > file3

Это не очень эффективно (поскольку файл2 будет читаться снова и снова), но это может быть достаточно для вас. Если вы хотите увеличить скорость, я бы предложил использовать более мощный язык сценариев, который позволяет читать file2 на карте, которая быстро позволяет идентифицировать строки для данного идентификатора.

Здесь версия Python этой идеи:

queryByID = {}

for line in file('file2'):
  lastEquals = line.rfind('=')
  semicolon = line.find(';', lastEquals)
  id = line[lastEquals + 1:semicolon]
  queryByID[id] = line.rstrip()

for line in file('file1'):
  id = line.rstrip()
  if id in queryByID:
    print queryByID[id]

Ответ 4

Я предлагаю использовать язык программирования, такой как Perl, Ruby или Python.

В Ruby решение, считывающее оба файла (f1 и f2) только один раз, может быть:

idxes = File.readlines('f1').map(&:chomp)

File.foreach('f2') do | line |
  next unless line =~ /where ri=(\d+);$/
  puts line if idxes.include? $1
end

или с Perl

open $file, '<', 'f1';
while (<$file>) { chomp; $idxs{$_} = 1; }
close($file);

open $file, '<', 'f2';
while (<$file>) {
    next unless $_ =~ /where ri=(\d+);$/;
    print $_ if $idxs{$1};
}
close $file;

Ответ 5

Вышеупомянутые awk/grep-решения были медленными или голодными на моей машине (файл1 10 ^ 6 строк, файл2 10 ^ 7 строк). Поэтому я придумал SQL-решение, использующее sqlite3.

Поверните файл2 в файл в формате CSV, где первым полем будет значение после ri=

cat file2.txt  | gawk -F= '{ print $3","$0 }' | sed 's/;,/,/' > file2_with_ids.txt

Создайте две таблицы:

sqlite> CREATE TABLE file1(rowId char(10));
sqlite> CREATE TABLE file2(rowId char(10), statement varchar(200));

Импортируйте идентификаторы строк из файла1:

sqlite> .import file1.txt file1

Импортируйте инструкции из файла2, используя "подготовленную" версию:

sqlite> .separator ,
sqlite> .import file2_with_ids.txt file2

Выберите все и оставьте операторы в таблице file2 с подходящей строкой в ​​таблице file1:

sqlite> SELECT statement FROM file2 WHERE file2.rowId IN (SELECT file1.rowId FROM file1);

Файл 3 может быть легко создан путем перенаправления вывода в файл перед выдачей оператора select:

sqlite> .output file3.txt

Данные теста:

sqlite> select count(*) from file1;
1000000
sqlite> select count(*) from file2;
10000000
sqlite> select * from file1 limit 4;
1610666927
1610661782
1610659837
1610664855
sqlite> select * from file2 limit 4;
1610665680|update TABLE_X set ATTRIBUTE_A=87 where ri=1610665680;
1610661907|update TABLE_X set ATTRIBUTE_A=87 where ri=1610661907;
1610659801|update TABLE_X set ATTRIBUTE_A=87 where ri=1610659801;
1610670610|update TABLE_X set ATTRIBUTE_A=87 where ri=1610670610;

Без создания каких-либо индексов оператор select занял около 15 секунд на 64-битной машине Ubuntu 12.04 AMD A8 1.8HGz.

Ответ 6

Возможно, попробуйте AWK и используйте номер из файла 1 в качестве ключа, например, простого script

Первый script будет производить awk script:
awk -f script1.awk

 {
   print "\$0 ~ ",$0,"{ print \$0 }" > script2.awk;
 }

а затем вызовите файл script2.awk с файлом

Ответ 7

## сообщает любые строки, содержащиеся в < файл 1 > отсутствует в < файл 2 >

IFS=$(echo -en "\n\b") && for a in $(cat < file 1>); 
do ((\!$(grep -F -c -- "$a" < file 2>))) && echo $a; 
done && unset IFS

или делать то, что хочет ассер, снять отрицание и перенаправить

(IFS=$(echo -en "\n\b") && for a in $(cat < file 1>); 
do (($(grep -F -c -- "$a" < file 2>))) && echo $a; 
done && unset IFS) >> < file 3>