grep regex pattern соответствует каждой строке, где только все совпадения появляются и печатаются в одной строке

242
Sina

пытаясь извлечь несколько шаблонов на строку, из файла журнала. Я пытаюсь извлечь первую временную отметку и два или три других совпадения, но я хочу иметь возможность печатать совпадения только из тех строк, где появляются все совпадения. Есть ли одна команда grep, с которой я могу сделать это, или я должен пройти через каждую строку?

Моя строка журнала такая

2018-08-07 08:55:20 ERROR[t-dispatcher-24] - Error while processing message: code:[RequestTimeout], message:[{"from_addr_type": null, "transport_name": "999_abc_999_2_1", "in_reply_to": null, "group": null, "timestamp": "2018-08-07 07:55:19.795748", "from_addr": "341231231234", "message_type": "user_message", "helper_metadata": {}, "to_addr": "ABCD", "to_addr_type": null, "session_id": "157692", "content": "0013091779", "routing_metadata": {}, "message_version": "20110921", "transport_type": "XXXX", "provider": "abc_somewhere", "transport_metadata": {"abc_somewhere_XXXX": {"clientId": "XXXX157692", "starCode": "999", "session_id": "157692", "phase": "2", "dcs": "15", "requestId": "157692"}}, "session_event": "resume", "message_id": "5d9cab5353ff449783a737e8390a690b"}]

Я хочу иметь возможность извлекать определенные группы, такие как отметка времени в начале, разделы "content" и "to_addr".

Я придумал это: grep -oP '(\d-\d-\d\s\d:\d:\d)|"to_addr":"\K(\d+)|"content":\K"(.+?)"' | tr -d '\n'

Но я не могу выбрать только те линии, где существуют все три соответствия шаблону. Пожалуйста, что я делаю не так? Я ожидаю слишком многого?

0

1 ответ на вопрос

0
Toto

Вы используете ИЛИ |между вашими шаблонами, вы хотите И.

В вашем паттерне вы ищете, "to_addr":"\K(\d+)но в вашем примере значение to_addrравно ABCDтак, что оно не совпадает с, \d+и между "to_addr:и "ABCD", то же самое, есть пробел content.

Если to_addrвсегда раньше content:

grep -P '^\d-\d-\d\s\d:\d:\d.*?"to_addr": "\d+.*?"content": ".+?"' 

Остальное использовать Lookaheads:

grep -P '^\d-\d-\d\s\d:\d:\d(?=.*?"to_addr": "\d+)(?=.*?"content": "(.+?)")' 

Если вы хотите печатать только совпадения, я предлагаю Perl с одним вкладышем:

perl -ane 'print "$1\t$2\t$3\n" if (/^(\d-\d-\d\s\d:\d:\d)(?=.*?"to_addr": "(\d+))(?=.*?"content": "(.+?)")/)' file 
Большое спасибо! Это позволяет мне идеально выбирать линии, но как я могу напечатать только совпадения из каждой строки в одной строке? Sina 5 лет назад 0
@ Сина: Я предлагаю использовать Perl однострочное, см. Мое редактирование. Toto 5 лет назад 0
Спасибо! Очень красивый однострочник! Я сделал небольшой скрипт: `while IFS = '' read -r line; do value0 = $ (вывести «$ line» | grep -oP '^ (\ d - \ d - \ d \ s \ d : \ d : \ d ) '); value1 = $ (echo "$ line" | grep -oP '"to_addr": "\ K (\ d +)'); value2 = $ (echo" $ line "| grep -oP '" content ":" \ K ( . +? ") '); printf"% s% s% s \ n "" $ value0 "" $ value1 "" $ value2 "; сделано> output_file` но я всегда благодарен за получение perl. Sina 5 лет назад 0

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