Bash. Обработка текста. - Форум успешных вебмастеров - GoFuckBiz.com
 
 
Форум успешных вебмастеров - GoFuckBiz.com

  Форум успешных вебмастеров - GoFuckBiz.com > Бизнес-решения > Скрипты, программы и технические решения
Дата
USD/RUB93.4409
BTC/USD64732.6476
Скрипты, программы и технические решения Обсуждаем скрипты, программы и новые технологии.

Закрытая тема
Опции темы Опции просмотра
Старый 01.07.2017, 23:30   #1
capturis
Senior Member
 
Аватар для capturis
 
Регистрация: 25.11.2013
Сообщений: 272
Бабло: $47235
Отправить сообщение для capturis с помощью Telegram Отправить сообщение для capturis с помощью Jabber
По умолчанию Bash. Обработка текста.

Уже выкладывал этот материал на другом форуме но так-как он в настоящий момент закрыт, а посылать куда-то надо то пусть и здесь тоже будет.

Все чаще стал обращать внимание на посты на разных форумах формата "как убрать дубли из файла", "как почистить текст от мусора" и т.п. примитивные задачи, которые становятся трудно разрешимыми при увеличении исходных файлов свыше определенного предела.
Очевидно те, кто задает такие вопросы, не знают как это делается, а я знаю и с удовольствием расскажу.
Речь пойдет об утилитах командной строки линукс-подобных операционных систем. Для эффективной работы с большими, нет не так - с ОГРОМНЫМИ файлами (логи серверов, почты etc.), в линуксах давным-давно разработаны специальные, крайне эффективные программы, способные за считанные мгновения перелопатить гигантский объем информации.
При этом как правило сохраняются очень маленькие требования к железу.

Итак, приступим.
Первая задача, с которой сталкивается начинающий дорвейщик - где взять ключи. Для примера возьмем максимальную базу eng. ключей от букварикса. Количество слов: 3 421 316 689
Популярные решения вроде кейвордкипера ее не тянут(или требуют кучу оперативки, хз). А нам надо выдернуть из нее нужные ключи.
Для этого есть утилита grep.
Она умеет искать в текстовом файле или в папке (папках рекурсивно) совпадения по маске, в том числе с использованием регулярных выражений.
Полностью команда будет выглядеть например так:
Код:
grep essay EnglishKeywordsMax.txt > essay.txt
Чтобы было понятно, какая у этого всего скорость:
Код:
time grep essay EnglishKeywordsMax.txt |wc -l
1419442

real	14m27.661s
user	2m49.360s
sys	1m32.008s
Менее 15 минут на 3,4 миллиарда строк. Неплохо, да?

Далее предположим, что нам надо полученные ключи почистить от мусора. Под мусором можно понимать разное в зависимости от задачи. Здесь будем считать мусором любые символы, отличающиеся от букв, цифр и пробелов.
Для замены символов используется команда sed.
Она обрабатывает каждую строку по порядку, пока не дойдет до конца файла.
В рамках нашей задачи будет выглядеть примерно так:

Код:
sed 's/[^a-zA-Zа-яА-Я0-9\ ]\+/ /g;s/^[ ]*//;s/[ ]*$//;s/\ \{2,\}/\ /g' file1.txt > file2.txt
Здесь все лишние символы заменяются пробелом. И сразу же убираются пробелы в начале и в конце строки, а также образовавшиеся после замены двойные пробелы.
После удаления мусора могли возникнуть дубли строк, чтобы их удалить можно воспользоваться командой sort.
Работает очень просто. Сортирует входящий поток(файл) и при надобности оставляет только уникальные строки (ключ "-u").

Код:
sort -u file1.txt > file2.txt
Естественно, поддерживается перенаправление вывода и можно объединить эту команду в конвеер с предыдущей.

Код:
sed 's/[^a-zA-Zа-яА-Я0-9\ ]\+/ /g;s/^[ ]*//;s/[ ]*$//;s/\ \{2,\}/\ /g' file1.txt | sort -u > file2.txt
В дело пускать отсортированный по алфавиту список ключей нельзя. Надо перемешать:

Код:
sort -R file1.txt > file2.txt
Вроде все норм, но великоват файлик, надо порезать split:

Код:
split -l 10000 --additional-suffix=.txt file.txt
Разобьет файл на части по 10000 строк в каждой и добавит нужное расширение.
Здесь мы вкратце познакомились с обработкой строк, а что же делать если надо обработать CSV? Тут тоже есть методы.
Вырезать первый столбец из файла с разделителем "точка с запятой" cut:

Код:
cut -d';' -f1 file1.csv > file2.txt # аналогично 3 и 5 столбцы:
cut -d';' -f3,5 file1.csv > file2.csv
Такого же результата можно добиться с помощью прогаммы awk:

Код:
awk -F';' '{print $1}' file1.csv > file2.txt 
awk -F';' '{print $3 ";" $5}' file1.csv > file2.csv
Эта программа работает чуть медленнее, зато имеет гораздо более широкие возможности. Например можно вывести значение первого столбца строки, во втором столбце которой присутствует нужная маска:


Код:
awk '$2 ~ /LEGO/ {print $1}' file1.csv > file2.csv
Вообще awk и sed имеют слишком много возможностей, чтобы пытаться описать их за один раз, да и написано в интернете по этому поводу уже немало. Кому будет интересно найдут. Вот для начала:
awk
sed

Еще пара прикладных примеров:
Бывает нужно сгенерировать базу кейвордов из исходных. Допустим сделать список формата "купить X в городе Y"
У нас есть список товаров и список городов в файлах. Читаем файл с товарами, заменяем начало строки на нужную фразу с подстановкой и записываем в файл:

Код:
cat товары.txt | while read line;do sed "s/^/купить $line в /" города.txt; done > 3.txt
Будьте осторожны, не надо скармливать этому скрипту слишком большие файлы - на выходе получается произведение строк. Хотя ничего страшного не случится, лишь бы места на диске хватало

Проверка статистики поисковой выдачи.
Допустим есть кучка запросов, по которым надо проверить выдачу и узнать, какие сайты в топе. Чем больше запросов, тем интереснее.
Парсим топ до требуемой глубины. Складываем в один файл в формате "ссылка;запрос"

Код:
#Выводим все ссылки, по убыванию:
cut -d';' -f1 top3.txt | sort | uniq -c | sort -nr > link.txt
#Выводим все домены, по убыванию:
cut -d'/' -f3 top3.txt | sort | uniq -c | sort -nr > domains.txt
Вообще лично я считаю наиболее значительной возможностью, которую даёт консоль - это использование потока ввода/вывода. С помощью этого механизма можно собирать довольно сложные конструкции.
Например есть некая база урлов. Надо разложить её по доменным зонам в разные файлы. Выглядеть это будет примерно так:
Код:
cut -d'/' -f3 file.txt |rev|cut -d'.' -f 1|rev| sort -u | while read line;do awk -F'/' "\$3 ~ /\."$line"$/ {print \$0}" file.txt > "$line".txt;done
Здесь мы сначала вырезаем из файла со ссылками домены. cut
Потом переворачиваем каждую строку. rev
Отсекаем всё после точки. cut
Переворачиваем обратно. rev
Удаляем дубли. sort
Читаем получившийся список зон построчно while read line и передаем его в awk, которая при совпадении условия пишет строку из файла урлов в файл с именем зоны.

Ну и немного практки а-ля хрумовский анализатор баз.
Это чудо инженерной мысли состоит из двух частей. Первая(checker.sh или как угодно) читает список урлов и запускает вторую в нужное число потоков.

Код:
#!/bin/bash
cat urls.txt| xargs -P 150 -n1 ./worker.sh
# параметр -P задаёт кол-во потоков
Вторая(worker.sh или поменять на свое в checker.sh) качает страницу и ищет совпадения в контенте. Если находит, записывает урл. Плюс пишет все обработанные урлы в лог, чтобы отслеживать прогресс.

Код:
#!/bin/bash
match="-e essay -e papers -e college"
# шаблон поиска(урл и т.п.)
data=`wget -t 1 -T 5 --quiet -O - $1 |grep -m 1 $match`
# -t - количество попыток
# -T таймаут в секундах
echo $1 >> log.txt
if [ -n "$data" ]
then
    echo $1 >> result.txt
fi
Запускать, понятное дело, только первую.

Здесь только малая часть того, что можно сделать с текстом в линуксе, используя встроенные утилиты.

Если появятся трудности с освоением или нет на это самое освоение времени - контакты в профиле. Договоримся.
capturis вне форума  
Старый 02.07.2017, 12:53   #2
ustas
Member
 
Аватар для ustas
 
Регистрация: 21.08.2016
Адрес: Севастополь, Украина
Сообщений: 58
Бабло: $16775
По умолчанию

shuf еще для перемешивания, sort -R на больших объемах тупит
__________________
Паливо тем v2.0
ustas вне форума