Найти содержимое одного файла из другого файла в 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 записей в час.
Есть ли более быстрый способ сделать это?
Ответы
Ответ 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>