Имеется файл 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совпадает, который в нем… я не могу придумать реализуемый алгоритм…
Последние комментарии
-
OlegL, 17 декабря 2023 года в 15:00 →
Перекличка
21
-
REDkiy, 8 июня 2023 года в 9:09 →
Как «замокать» файл для юниттеста в Python?
2
-
fhunter, 29 ноября 2022 года в 2:09 →
Проблема с NO_PUBKEY: как получить GPG-ключ и добавить его в базу apt?
6
-
Иванн, 9 апреля 2022 года в 8:31 →
Ассоциация РАСПО провела первое учредительное собрание
1
-
Kiri11.ADV1, 7 марта 2021 года в 12:01 →
Логи catalina.out в TomCat 9 в формате JSON
1
DevOps as a Service from Palark

Раскромсать на несколько файлов по границам <PROD_TYPE></PROD_TYPE> и искать ID в них?
отличный вариант… как-то думал, как бы так реализовать, но тоже не додумался.
awk сделает выборку по границам <PROD_TYPE></PROD_TYPE>, а как каждый результат в отдельный фай можно закинуть?
www.unix.com/shell-programming-and-scripting/24859-awk-output-file.html
Тут вот предлагают вариант в последнем посте. Попробовал, вроде работает.
Век живи, век учись, я такого про awk не знал :)
не подойдет, потому что каждую отдельную команду в свой файл можно выполнить… а вот одну команду как-то разбить…
Например:
awk ' ($0~/\<cashflow\>/ && $0!~/\//), ($0~/\<cashflow\>/ && $0~/\//) { print $0 }' tads > tmp
выведет все блоки <cashflow>…</cashflow> в файл «tmp», а вот как вывести каждую секцию в отдельный файл?
awk 'BEGIN{number=0} ($0~/\<cashflow\>/ && $0!~/\//), ($0~/\<cashflow\>/ && $0~/\//) { print $0 > number;number=number+1 }' tads
Как-то так? Это должно распихать куски в нумерованные файлы.
Очень близко!!!
Теперь каждая строка попадает в отдельный файл… это хорошо, но выборка написана для блока:
<cashflow>
…
</cashflow>
и нужно что бы один блок в один файл бросало — это по-сложнее и у меня не получилось…
и кол-во строк может быть разное… между тегами…
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. И попросить конкретный пример устройства, чтобы не отрываться далеко от практики.
Роутер называется, бытовой :).
Проверил на openwrt — awk есть, из busybox. pcregrep — нету.
PS. Обработка html и xml regexp-ами возможна только в случае их валидности и ведёт к безумию. Это круче чем Ктулху.
> Проверил на 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» в продакшне яйца бы оторвали.
Я не препод. По крайней мере не в этом случае. Иногда подкидываю подобные задачи. Я бы такое решение зачёл (скорее всего, по результатам беседы), но поинтересовался бы альтернативами.
Я не точно выразился, я хотел сказать что для обработки xml/html есть свой набор тулов. И писать это самому на regex-ах стоит только если ОЧЕНЬ точно понимаешь зачем это надо.
PS. и оффтопик — С чисто эстетической точки зрения мне json больше нравится как формат передачи данных. Его читать проще.
Да, есть свои тулзы. Но это не xml и не html. Поэтому приходится писать свой парсер. Можно awk, можно регекспы. Ваша реакция мне напоминает весьма распространённую regexp-фобию. Эта фобия имеет весьма серьёзные основания, но не в этом случае. Требуемый регексп проще awk решения, он не требует временных файлов — это его преимущества. И кроме того этот случай не подлежит усложнению. То есть можно попробовать расширить, например, чтобы делать различные выборки, вплоть до того что SQL-синтаксис для запросов прикрутить. Но если такая проблема встанет, то это выльется в ужас что на awk, что на regexp’ах. Практически будет лучше пересмотреть формат и, либо перейти на хранение бд в чём-нибудь типа sqlite, либо полноценный xml использовать. И оба таких «апгрейда» приведут к ненужности текущего решения.
Вопрос в том, что если это учебная задача — тогда да «И кроме того этот случай не подлежит усложнению».
А в реальной жизни обычно получается через некоторое время — «ой, (а нельзя ли|нужно) сюда ещё вот это прикрутить. позавчера». Ну а так как позавчера, то переписывать грамотно получится не скоро, если вообще получится. Результаты такого обычно печальны, по крайней мере в долгосрочной перспективе. Поэтому лучше сразу брать правильный тул. Кстати да, присоединяюсь к рекомендации sqlite.
PS. Признаю, у меня есть некоторая regexp-фобия. :)
не как не процеситсья…
может из-за ID.
Пример ID: CS_EC.
название файла, по которому поиск пишу в самом конце? после » ' «?
Ну, у меня вписана 2 в качестве ID. Надо вписать что-нибудь иное. Должно работать. Файл да, вписывать последним аргументом, как и для grep.
не получается( еще поковыряюсь вечером…
Если вы пример rs.xml выложите полностью, то я тоже могу глянуть в чём проблема. У меня выдирает:
а за что здесь отвечает:
(?>.*?(?=<ID>))?
и в теге ID зачем добавлять \s* ???
извеняюсь — ниже не прочел пост..
Если регексп разобрать на части:
(?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> — это собственно финал, определяющий когда остановиться.
структуру я понял.
файл приложить не могу, но вот кусок, непосредственно, по которому должно найти мне результат:
</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
и результат пустой…
не могу в упор понять, где ошибаюсь…
Во входном потоке id строчными. Либо в регекспе надо изменить ID на id, либо к опции -M добавить -i, получив pcregrep -Mi.
ой… надо же было не заметить) спасибо большое!!!
есть! но! выбирает не для всех ID))
для этого выбирает
XGP_EC
XGP_BS
RC_EC
IV_HO
для этого нет
XGP_HO
выборку делаю по шаблону:
(?s)<PROD_TYPE(?>.*?(?=<id>)).*?<id>XGP_HO</id>.*?</PROD_TYPE>
почему может не работать только для нескольких ID?
нет там различий в структуре…
кол-во символов в блоке для найденого 8208
кол-во символов в блоке для ненайденого 8238
из-за этого проблемы быть не может
Да, из-за этого могут быть проблемы. В man pcregrep написано об этом, он буферизирует по 8k байт. С этим можно бороться поставив --buffer-size=N, где N — число байт.
ясно. а где поставить нужно?
Промеж опций pcregrep. pcregrep -Mi -buffersize=20000 …
Спасибо! Пробую!
не хочет(((
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.
в --help нет опции отвечающей за буфер…
--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.)
да. это читал… не знаю как указать
--buffer-size=number
не хочет его воспринимать(
pcregrep -Mi --buffer-size=20000 '(?s)<PROD_TYPE>(?>.*?(?=<ID>))<ID>\s*CS_EC\s*</ID>.*?</PROD_TYPE>' tmp.xml
Работает. Сложно сказать без дополнительной информации, что там у вас не так.
как жаль… сервер не мой, и у меня может не быть доступа к конфигу буфера…
сервер удаленно в другой стране стоит…
Не может не быть доступа. Такие ограничения могут быть установлены разве что по использованию оперативки процессом, но 20kb — это не тот объём, который может повлиять. 20-100Mb — может. Чисто теоретически. А 20Kb — нет.
я понимаю, что числа незначетельные…
я выполняю не на своем ПК а на сервере… и не удается выполнить…
pcregrep-Mi --buffer-size=20000-f template_file file.xml
доходя до буквы «b» пишет, что такой здесь быть не может(
версия pcregrep меньше 8.13? Другие long-options, типа --color, pcregrep кушает?
а как посмотреть версию???
пишу long-option --color=«что-то там»… что-то там» пишет, что не правильное, видимо в неправильном формате задаю.
а на --color не ругается…
> а как посмотреть версию???
pcregrep --version
pcregrep version 7.8 2008-09-05
О! 2008-го года. Да, совершенно определённо все проблемы из-за этого.
Судя по upstream-tracker.org/changelogs/pcre/8.36/changelog.html опция --buffer-size была добавлена в версии 8.13 в 2011 году.
А что за сервер? Если он так лениво обновляется, то его вснепременно нужно взломать и получить рутшелл. Даже не для того, чтобы делать гадостей, а ради собственного удовлетворения: тем кто не занимается взломами постоянно, само по себе получение рутшелла может доставить массу радостей. Ну и обретение некоего опыта, который лишним не будет. В общем, если вам не приходилось заниматься этим ранее, то займитесь обязательно. А если это сервер, который держит препод, то, быть может, он оценит вашу заботу, если вы принесёте ему эксплоит, заточенный под его систему и объясните, как залатать дыры накатив обновления.
Большое спасибо за помощь — сам бы тут не разобрался))
Ломануть не получиться… сервер в европейском банке… хоть и слабый, но для подключения к нему — «крутые» firewalls…
Ну если в банке, то может и не стоит ломать. Банки они такие, они могут обидеться и через границу достанут. А файрволлы без разницы, у вас же есть шелл, вы уже прошли сквозь файрволлы.
да, прошел. НО там очень быстро таких достаю, примеры есть…
Это мне сервер по просьбе предоставили для обучения, вообще через этот и доступа может не куда не быть, может и потому заброшен… а я думаю, как задачи свои автоматизировать… учусь, развиваюсь)
Большое спасибо Вам за помощь, свой скил подтянул)
наверное из-за версии
пишет мне
Unknown option --buffer-size=20000
или тоже нашел где-то в нете
Unknown option --buffer-size=20K
хотя когда пытаюсь по ID найти блок по меньше, а не в 8000 строк, то по всем ID находит…
а если все таки есть ограничение, то как его пробить?
Скорее всего ограничения… как их можно победить?
я не совсем понимаю, что они ограничивают? возможный результат, или входной файл после 8к строк???