Имеется файл 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
Раскромсать на несколько файлов по границам <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 нет опции отвечающей за буфер…
Это из man pcregrep
И вот ещё про буфер, и -M:
да. это читал… не знаю как указать
--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к строк???