Нужно тянуть строки, содержащие шаблон в середине, но не в конце строки

Готов поспорить, что причина, по которой ваши скрипты занимают так много времени, заключается в том, что вы запускаетеuuidgen(илиcksum)для каждой строки. Много времени тратится впустую, просто запуская процессы для каждого из них.

Если поместить 5 млн строк формы {"name": "John%d", "surname": "Gates", "country": "Germany", "age": "20", "height": "180"}в файл в файловой системе tmpfs, следующий скрипт Python завершится за секунды:

#! /usr/bin/env python3

import hashlib
import sys
for line in sys.stdin:
    print(hashlib.md5(line.rstrip('\n').encode('utf-8')).hexdigest())

Исполнение:

$ time./foo.py < input > output
./foo.py < input > output  6.00s user 0.13s system 99% cpu 6.135 total
% wc -l input output
  5000000 input
  5000000 output
 10000000 total

Поскольку это Python, вы также можете декодировать строки в формате JSON -и вставлять в каждую из них идентификатор. Даже неэффективный код вроде:

#! /usr/bin/env python3

import hashlib
import json
import sys
for line in sys.stdin:
    l = line.rstrip('\n').encode('utf-8')
    o = json.loads(line)
    o["id"] = hashlib.md5(l).hexdigest()
    print(json.dumps(o))

Готово менее чем за минуту:

% time./foo.py < input > output
./foo.py < input > output  42.11s user 0.42s system 99% cpu 42.600 total

% head output 
{"name": "John1", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "2dc573ccb15679f58abfc44ec8169e52"}
{"name": "John2", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "ee0583acaf8ad0e502bf5abd29f37edb"}
{"name": "John3", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "a7352ebb79db8c8fc2cc8758eadd9ea3"}
{"name": "John4", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "2062ad1b67ccdce55663bfd523ce1dfb"}
{"name": "John5", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "5f81325c104c01c3e82abd2190f14bcf"}
{"name": "John6", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "493e0c9656f74ec3616e60886ee38e6a"}
{"name": "John7", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "19af9ef2e20466d0fb0efcf03f56d3f6"}
{"name": "John8", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "2348bd47b20ac6445213254c6a8aa80b"}
{"name": "John9", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "090a521b4a858705dc69bf9c8dca6c19"}
{"name": "John10", "surname": "Gates", "country": "Germany", "age": "20", "height": "180", "id": "fc3c699323cbe399e210e4a191f04003"}

Мои характеристики:

  • Процессор Intel® Core™ i7 -8700 с тактовой частотой 3,20 ГГц × 12
  • Память DDR4 2666 МГц

Сценарий, основанный на uuidgen-, едва смог закончить 500 тыс. строк за 4 минуты. Изменено для сохранения вывода:

#!/usr/bin/bash

while IFS= read -r line
do
   uuidgen -s --namespace @dns --name "$line"
done < input > uuid

Исполнение:

% timeout 240./foo.sh
% wc -l uuid
522160 uuid
0
28.07.2020, 01:32
3 ответа

Может быть проще использовать awkили sed, когда требуется несколько условий:

awk '!/8$/ && /8/' file

Это выбирает строки для печати на основе 2 условий :что они не соответствуют привязанному регулярному выражению 8$и соответствуют 8. Та же логика в sed:sed -n '/8$/!{/8/p;}'.

С sedи немного другой логикой:

sed '/8$/d; /8/!d' file

Это фильтрует строки, удаляя те, которые соответствуют 8$или не соответствуют 8. Та же логика в awk :awk '/8$/ || !/8/ {next} 1'.

или grepx2:

grep -v 8$ <file | grep 8

Отклонить строки, оканчивающиеся на 8, при первом проходе. Выберите строки, содержащие 8, со вторым проходом.

1
18.03.2021, 23:16

Вот так:

grep -E '8.+$' <FILE>
0
18.03.2021, 23:16

Ваши требования не ясны, но печатать строки, которые имеют 8в середине, независимо от того, есть ли у них также 8 в конце, что, как я думаю, вы хотите, просто быть:

grep '8.' file
1
18.03.2021, 23:16

Теги

Похожие вопросы