nixp.ru v3.0

18 октября 2017,
среда,
19:50:25 MSK

DevOps с компанией «Флант»
the_strelock написал 30 сентября 2014 года в 13:16 (2236 просмотров) Ведет себя неопределенно; открыл 1 тему в форуме, оставил 30 комментариев на сайте.

Имеется файл tm.csv

С форматом: xxx,yyy,zzz…

В шестой колонке содержаться ID.

 

Второй файл rs.xml

В нем «этиже» IDсодержаться в тегах <ID> & </ID>.

Теги ID по схеме помещены в теги <PROD_TYPE> &</PROD_TYPE> в них есть и другие…

<PROD_TYPE>

<ID>

</ID>

</PROD_TYPE>

 

 

Нужно по IDиз tm.csvвывести соответствующие секции <PROD_TYPE>из rs.xml.

 

(awk ' BEGIN {FS=«,»} {print $6} ' tm.csv) #получили все ID из tm.csv

 

Но нужно получить след. Картину:

ID

<PROD_TYPE>

<ID>

</ID>

</PROD_TYPE>

 

 

ID

<PROD_TYPE>

<ID>

</ID>

</PROD_TYPE>

 

Подскажите, пожалуйста, как по IDвывести целиком секцию <PROD_TYPE>к которой он принадлежит???

Grep с ключами -A и -Bне подходит, т.к.  Кол-во строк в тегах <PROD_TYPE>может сильно варьироваться…

Нужна какая-то выборка тегов <PROD_TYPE>с проверкой условий, что IDсовпадает, который в нем… я не могу придумать реализуемый алгоритм…

fhunter

Раскромсать на несколько файлов по границам <PROD_TYPE></PROD_TYPE> и искать ID в них?

the_strelock

отличный вариант… как-то думал, как бы так реализовать, но тоже не додумался.

awk сделает выборку по границам <PROD_TYPE></PROD_TYPE>, а как каждый результат в отдельный фай можно закинуть?

fhunter

www.unix.com/shell-programming-and-scripting/24859-awk-output-file.html

Тут вот предлагают вариант в последнем посте. Попробовал, вроде работает.

Век живи, век учись, я такого про awk не знал :)

the_strelock

не подойдет, потому что каждую отдельную команду в свой файл можно выполнить… а вот одну команду как-то разбить…

Например:

awk ' ($0~/\<cashflow\>/ && $0!~/\//), ($0~/\<cashflow\>/ && $0~/\//) { print $0 }' tads > tmp

 

выведет все блоки <cashflow>…</cashflow> в файл «tmp», а вот как вывести каждую секцию в отдельный файл?

fhunter

awk 'BEGIN{number=0} ($0~/\<cashflow\>/ && $0!~/\//), ($0~/\<cashflow\>/ && $0~/\//) { print $0 > number;number=number+1 }' tads

Как-то так? Это должно распихать куски в нумерованные файлы.

the_strelock

Очень близко!!!

Теперь каждая строка попадает в отдельный файл… это хорошо, но выборка написана для блока:

<cashflow>

</cashflow>

и нужно что бы один блок в один файл бросало — это по-сложнее и у меня не получилось…

и кол-во строк может быть разное… между тегами…

rgo

pcregrep -M '(?s)<PROD_TYPE>(?>.*?(?=<ID>))<ID>2</ID>.*?</PROD_TYPE>'

Эта команда позволяет выдрать запись для ID == 2. Если между <ID> и </ID> могут быть ещё пробелы или переводы строк, то надо это отметить, заменив 2 на что-то типа \s*2\s*

При этом pcregrep — часть libpcre, и я полагаю, что он есть в любой системе. Ну, это я к тому, что задачка, как я понимаю студенческая, и препод может начать возмущаться на использование pcregrep. Но формально задача на *nix-шелл, а libpcre стоит на любом десктопе/сервере. Проблемы могут быть разве со встраиваемыми системами, но об этом преподу можно не напоминать, а если он сам вспомнит, то можно спросить, что это за встраиваемая система с awk’ом на борту и без libpcre. И попросить конкретный пример устройства, чтобы не отрываться далеко от практики.

fhunter

Роутер называется, бытовой :).

Проверил на openwrt — awk есть, из busybox. pcregrep — нету.

PS. Обработка html и xml regexp-ами возможна только в случае их валидности и ведёт к безумию. Это круче чем Ктулху.

rgo

> Проверил на openwrt — awk есть, из busybox. pcregrep — нету.

Нехрен перешивать с заводской прошивки. :P

Вы препод, задавший эту задачку? :)

Я думаю, что нет. А раз так, то поясню, что то «обоснование» использования pcre, которое я привёл, призвано на самом деле не «обосновать», а показать, что ошибка совершённая студентом выходит за рамки курса — ну, не знает ещё студент всего спектра *nix-устройств. При этом, студент показал изворотливость ума, способность решить задачу и общую ориентацию на практику при решении практических задач, и поэтому надо быть сильно неадекватным преподом, чтобы в результате не зачесть решение. Вероятно, придётся некоторое время поспорить с преподом, и тут будут влиять не только знания, но и социальные навыки. Но это даже хорошо: вообще полезно выносить мозги преподам.

> Обработка html и xml regexp-ами возможна только в случае их валидности и ведёт к безумию. Это круче чем Ктулху.

Вы ведь глупость сказали. regexp’ами можно обрабатывать очень широкий диапазон грамматик. Про валидность html/xml регекспы не знают ничего. Так же как и awk между прочим. И обоим инструментам, простите за выражение, насрать как называется синтаксис, в котором выдержан входной поток. Наш регексп или awk-скрипт определяют грамматику, ориентированную на задачу грамматику. Круче чем Ктулху — это если мы попытаемся определить грамматику сходную по сложности с xml, и это будет плохой идеей в любом случае, будем ли мы писать на awk, или на регекспах.

Если бы речь шла о валидном xml, то есть xmllint, который, AFAIR может выдирать из xml-документа ноды по выражениям xpath — и это было бы превосходнейшим способом работы с xml-документом. Но здесь не тот случай — судя по тому, что я вижу в стартовой задаче в качестве примера — ни о каком валидном xml там речи не идёт. Ни тебе стартового doctype, ни единого нода на собственно тело. Кстати на этот счёт преподу тоже можно вынести мозг — за такой «xml» в продакшне яйца бы оторвали.

fhunter

Я не препод. По крайней мере не в этом случае. Иногда подкидываю подобные задачи. Я бы такое решение зачёл (скорее всего, по результатам беседы), но поинтересовался бы альтернативами.

Я не точно выразился, я хотел сказать что для обработки xml/html есть свой набор тулов. И писать это самому на regex-ах стоит только если ОЧЕНЬ точно понимаешь зачем это надо.

PS. и оффтопик — С чисто эстетической точки зрения мне json больше нравится как формат передачи данных. Его читать проще.

rgo
fhunter
Я не точно выразился, я хотел сказать что для обработки xml/html есть свой набор тулов. И писать это самому на regex-ах стоит только если ОЧЕНЬ точно понимаешь зачем это надо.

Да, есть свои тулзы. Но это не xml и не html. Поэтому приходится писать свой парсер. Можно awk, можно регекспы. Ваша реакция мне напоминает весьма распространённую regexp-фобию. Эта фобия имеет весьма серьёзные основания, но не в этом случае. Требуемый регексп проще awk решения, он не требует временных файлов — это его преимущества. И кроме того этот случай не подлежит усложнению. То есть можно попробовать расширить, например, чтобы делать различные выборки, вплоть до того что SQL-синтаксис для запросов прикрутить. Но если такая проблема встанет, то это выльется в ужас что на awk, что на regexp’ах. Практически будет лучше пересмотреть формат и, либо перейти на хранение бд в чём-нибудь типа sqlite, либо полноценный xml использовать. И оба таких «апгрейда» приведут к ненужности текущего решения.

fhunter

Вопрос в том, что если это учебная задача — тогда да «И кроме того этот случай не подлежит усложнению».

А в реальной жизни обычно получается через некоторое время — «ой, (а нельзя ли|нужно) сюда ещё вот это прикрутить. позавчера». Ну а так как позавчера, то переписывать грамотно получится не скоро, если вообще получится. Результаты такого обычно печальны, по крайней мере в долгосрочной перспективе. Поэтому лучше сразу брать правильный тул. Кстати да, присоединяюсь к рекомендации sqlite.

PS. Признаю, у меня есть некоторая regexp-фобия. :)

the_strelock

не как не процеситсья…

может из-за ID.

Пример ID: CS_EC.

название файла, по которому поиск пишу в самом конце? после » ' «?

rgo

Ну, у меня вписана 2 в качестве ID. Надо вписать что-нибудь иное. Должно работать. Файл да, вписывать последним аргументом, как и для grep.

the_strelock

не получается( еще поковыряюсь вечером…

rgo

Если вы пример rs.xml выложите полностью, то я тоже могу глянуть в чём проблема. У меня выдирает:

[rgo ~]$ pcregrep -M '(?s)<PROD_TYPE>(?>.*?(?=<ID>))<ID>\s*CS_EC\s*</ID>.*?</PROD_TYPE>' tmp.xml 
<PROD_TYPE>
  бла-бла-бла
  <ID>
CS_EC </ID> </PROD_TYPE>


 

the_strelock

а за что здесь отвечает:

(?>.*?(?=<ID>))?

и в теге ID зачем добавлять \s* ???

the_strelock

извеняюсь — ниже не прочел пост..

rgo

Если регексп разобрать на части:

(?s) — управляющая директива, которая (вместе с опцией -M) говорит символу. съедать переводы строк

<PROD_TYPE> — то что мы ищем начинаетя именно с этой строки

(?>.*?(?=<ID>)) — это сложнее. По-идее это .*? — не-greedy версия .*, но такая .*?, за которой сразу следует <ID>, для этого используется lookahead (?=<ID>). При этом всё засунуто в (?>…), для того, чтобы регексп бы найдя lookahead’ом первый <ID> после <PROD_TYPE> считал бы что это именно то вхождение, которое требуется, и, соответственно, обработав оставшуюся часть регекспа и проверив совпадение ID’а, либо решил что так оно и надо, либо сбросил бы состояние и начал бы с текущей позиции искать новое вхождение _всего_ регекспа. Без этой замороки, если просто написать .*?, под этот регексп попадёт строка начиная с первого <PROD_TYPE> и до закрывающего тега </PROD_TYPE> в нужном ноде.

<ID>2</ID> — это часть регекспа, которая проверяет ID. Её надо заполнять скриптом, который знает нужные ID, возможно проверку нужно усложнить, учтя возможные пробелы, я писал об этом выше.

.*? — сожрёт всё что угодно, но с одним нюансом: это non-greedy версия .* Разница в том, что .* сожрёт всё до последнего найденного </PROD_TYPE>, .*? сожрёт всё до первого найденного, а именно это нам и надо. По идее тут задача та же, что и в позапрошлом абзаце — сожрать минимум, но здесь всё гораздо проще, вследствие алгоритма работы регекспа, который парсит поток с начала до конца: в этот момент уже известно что точка во входном потоке, к которому привязалось начало регекспа то самое, которое нам надо, и нам не надо сбрасывать парсер на старт регекспа по каким-то сложным условиям.

</PROD_TYPE> — это собственно финал, определяющий когда остановиться.

 

the_strelock

структуру я понял.

файл приложить не могу, но вот кусок, непосредственно, по которому должно найти мне результат:

 

</feature>

<PROD_TYPE>

<id>CS_EC</id>

<source_system>RAN-EU</source_system>

</PROD_TYPE>

</trade>

<extended_attributes xmlns="">

<et:extended_attribute>

<et:key>dateAttributeInstrument</et:key>

<et:value/>

 

что находиться до или после — не важно ведь…

 

пишу pcregrep -M '(?s)<PROD_TYPE>(?>.*?(?=<ID>))<ID>\s*CS_EC\s*</ID>.*?</PROD_TYPE>' tmp.xml

и результат пустой…

 

не могу в упор понять, где ошибаюсь…

rgo

Во входном потоке id строчными. Либо в регекспе надо изменить ID на id, либо к опции -M добавить -i, получив pcregrep -Mi.

the_strelock

ой… надо же было не заметить) спасибо большое!!!

the_strelock

есть! но! выбирает не для всех ID))

для этого выбирает

XGP_EC

XGP_BS

RC_EC

IV_HO

для этого нет

XGP_HO

 

выборку делаю по шаблону:

(?s)<PROD_TYPE(?>.*?(?=<id>)).*?<id>XGP_HO</id>.*?</PROD_TYPE>

 

почему может не работать только для нескольких ID?

 

the_strelock

нет там различий в структуре…

кол-во символов в блоке для найденого 8208

кол-во символов в блоке для ненайденого 8238
из-за этого проблемы быть не может

rgo

Да, из-за этого могут быть проблемы. В man pcregrep написано об этом, он буферизирует по 8k байт. С этим можно бороться поставив --buffer-size=N, где N — число байт.

the_strelock

ясно. а где поставить нужно?

 

rgo

Промеж опций pcregrep. pcregrep -Mi -buffersize=20000 …

the_strelock

Спасибо! Пробую!

the_strelock

не хочет(((

pcregrep: Unknown option letter 'b' in «-buffersize=20000»

Usage: pcregrep [-ABCcDdeFfHhilLMNnoqrsuVvwx] [long options] [pattern] [files]

Type `pcregrep --help' for more information and the long options.

the_strelock

в --help нет опции отвечающей за буфер…

rgo
--buffer-size=number
                 Set  the  parameter that controls how much memory is used for
                 buffering files that are being scanned.


Это из man pcregrep

И вот ещё про буфер, и -M:

-M, --multiline
                 Allow patterns to match more than one line. When this  option
                 is given, patterns may usefully contain literal newline char‐
                 acters and internal occurrences of ^ and  $  characters.  The
                 output  for  a  successful match may consist of more than one
                 line, the last of which is the one in which the match  ended.
                 If the matched string ends with a newline sequence the output
                 ends at the end of that line.
When this option is set, the PCRE library is called in "mul‐ tiline" mode. There is a limit to the number of lines that can be matched, imposed by the way that pcregrep buffers the input file as it scans it. However, pcregrep ensures that at least 8K characters or the rest of the document (whichever is the shorter) are available for forward matching, and simi‐ larly the previous 8K characters (or all the previous charac‐ ters, if fewer than 8K) are guaranteed to be available for lookbehind assertions. This option does not work when input is read line by line (see --line-buffered.)


 

 

the_strelock

да. это читал… не знаю как указать

--buffer-size=number

не хочет его воспринимать(

rgo

pcregrep -Mi --buffer-size=20000 '(?s)<PROD_TYPE>(?>.*?(?=<ID>))<ID>\s*CS_EC\s*</ID>.*?</PROD_TYPE>' tmp.xml

Работает. Сложно сказать без дополнительной информации, что там у вас не так.

the_strelock

как жаль… сервер не мой, и у меня может не быть доступа к конфигу буфера…

сервер удаленно в другой стране стоит…

rgo

Не может не быть доступа. Такие ограничения могут быть установлены разве что по использованию оперативки процессом, но 20kb — это не тот объём, который может повлиять. 20-100Mb — может. Чисто теоретически. А 20Kb — нет.

the_strelock

я понимаю, что числа незначетельные…

я выполняю не на своем ПК а на сервере… и не удается выполнить…

pcregrep-Mi --buffer-size=20000-f template_file file.xml

доходя до буквы «b» пишет, что такой здесь быть не может(

rgo

версия pcregrep меньше 8.13? Другие long-options, типа --color, pcregrep кушает?

the_strelock

а как посмотреть версию???

пишу long-option --color=«что-то там»…  что-то там» пишет, что не правильное, видимо в неправильном формате задаю.

а на --color не ругается…

rgo

> а как посмотреть версию???

 

pcregrep --version

the_strelock

pcregrep version 7.8 2008-09-05

rgo

О! 2008-го года. Да, совершенно определённо все проблемы из-за этого.

Судя по upstream-tracker.org/changelogs/pcre/8.36/changelog.html опция --buffer-size была добавлена в версии 8.13 в 2011 году.

 

А что за сервер? Если он так лениво обновляется, то его вснепременно нужно взломать и получить рутшелл. Даже не для того, чтобы делать гадостей, а ради собственного удовлетворения: тем кто не занимается взломами постоянно, само по себе получение рутшелла может доставить массу радостей. Ну и обретение некоего опыта, который лишним не будет. В общем, если вам не приходилось заниматься этим ранее, то займитесь обязательно. А если это сервер, который держит препод, то, быть может, он оценит вашу заботу, если вы принесёте ему эксплоит, заточенный под его систему и объясните, как залатать дыры накатив обновления.

the_strelock

Большое спасибо за помощь — сам бы тут не разобрался))

Ломануть не получиться… сервер в европейском банке… хоть и слабый, но для подключения к нему — «крутые» firewalls…

rgo

Ну если в банке, то может и не стоит ломать. Банки они такие, они могут обидеться и через границу достанут. А файрволлы без разницы, у вас же есть шелл, вы уже прошли сквозь файрволлы.

the_strelock

да, прошел. НО там очень быстро таких достаю, примеры есть…

Это мне сервер по просьбе предоставили для обучения, вообще через этот и доступа может не куда не быть, может и потому заброшен… а я думаю, как задачи свои автоматизировать… учусь, развиваюсь)

the_strelock

Большое спасибо Вам за помощь, свой скил подтянул)

the_strelock

наверное из-за версии

the_strelock

пишет мне

Unknown option --buffer-size=20000

the_strelock

или тоже нашел где-то в нете

Unknown option --buffer-size=20K

the_strelock

хотя когда пытаюсь по ID найти блок по меньше, а не в 8000 строк, то по всем ID находит…

the_strelock

а если все таки есть ограничение, то как его пробить?

the_strelock

Скорее всего ограничения… как их можно победить?

the_strelock

я не совсем понимаю, что они ограничивают? возможный результат, или входной файл после 8к строк???