grep для повернення Nth та Mth рядків до та після матчу


12

Я знаю, що за допомогою grep я можу використовувати поля -Aта -Bвитягувати попередні та наступні рядки з сірника.

Однак вони натягують всі лінії між матчем, виходячи з того, що вказано багато ліній.

grep -r -i -B 5 -A 5 "match" 

Мені хотілося б отримати лише 5- й рядок перед матчем та 5- й рядок після матчу на додаток до узгодженої лінії, а не отримувати між ними рядки.

Чи є спосіб зробити це за допомогою grep?


1
Ви можете зробити це, проклавши в sed. Я щойно тестував це, і він працював, але він працював лише тоді, коли у файлі була одна точна відповідність: grep -r -i -B 5 -A 5 "match" | sed -e 1b -e '$!d'
Терранс

@ Спасибі, дякую за пропозицію, як ви згадуєте, оскільки я збираю 1000 рядків, це не вийде.
холліда

Я не думаю, що греп спрацює сам по собі ... Я працюю над сценарієм баш для вас
Джошуа Беснеатте

Нема проблем! Зацікавившись, які відповіді ви отримаєте. =)
Терранс

це в одному файлі чи в декількох файлах?
Джошуа Беснеатте

Відповіді:


1

Інструмент, який ви хочете використовувати, називається просіяти. Це в основному греп на стероїди. Гребіть паралельно. У Sift є величезна кількість варіантів робити саме те, що ви хочете - зокрема повернути певний рядок відносно відповідності, яка може / може не супроводжуватися / передувати деяким текстом.

Мене дивує, що просіяти не є основним гну, як це було написано мовою ходу, але встановлюється в Linux просто чудово. ІТ-паралельно здійснює пошук, використовуючи всю величезну кількість тексту в cpus, де для того, щоб зробити це, потрібно лише тиждень.

Просійте веб-сайт - див. Приклади


Ласкаво просимо до AskUbuntu, дякую за відповіді. Вам потрібно надати приклад CLI, який може вирішити цю конкретну проблему, а не надавати посилання на веб-сайт просіювання. Це післязапитання, спасибі.
Бернар Вей

12

Якщо:

cat file
a
b
c
d
e
f match
g
h
i match
j
k
l
m
n
o

Тоді:

awk '
    {line[NR] = $0} 
    /match/ {matched[NR]} 
    END {
        for (nr in matched)
            for (n=nr-5; n<=nr+5; n+=5) 
                print line[n]
    }
' file
a
f match
k
d
i match
n

+1, але ви могли б пояснити семантику /match/ {matched[NR]}? Я ніколи не бачив масив чи змінну як цілу команду. Чи вводить номер поточного запису кожного відповідного рядка в масив.
Джо

Це дивна дивність: якщо ви посилаєтесь на елемент масиву без призначення, цей ключ додається до масиву (без значення). Потім ця клавіша з’являється у виразі key in array. Що я роблю, це запам’ятовувати номери рядків, де з’являється візерунок
Гленн Джекман

6

Це в основному рішення Глена, але реалізовано разом з Bash, Grep та sed.

grep -n match file |
    while IFS=: read nr _; do
        sed -ns "$((nr-5))p; $((nr))p; $((nr+5))p" file
    done

Зауважте, що номери рядків менше 1 зроблять помилку sed, а номери рядків, що перевищують кількість рядків у файлі, змусять його нічого друкувати.

Це просто найменший мінімум. Щоб змусити його працювати рекурсивно та обробляти вищезазначені випадки з номером рядків, знадобиться певна робота.


6

Це неможливо зробити тільки grep. Якщо edє варіант:

ed -s file << 'EOF' 
g/match/-5p\
+5p\
+5p
EOF  

В основному сценарій говорить: для кожного матчу / матчу / надрукуйте рядок 5 рядків до цього, потім 5 рядків після цього, потім 5 рядків після цього.


5
@ubashu Ви думаєте, що ОП буде кориснішим, коли простий план "це не можна зробити з грепом"? Я надаю те, що, на мою думку, є гарною альтернативою для вирішення проблеми ОП. В довідковому центрі: "Що конкретно запитує питання? Переконайтеся, що ваша відповідь передбачає це - або життєздатну альтернативу. Відповідь може бути" не робити цього ", але також слід включити" спробувати це замість " . "
JoL

edце завжди відповідь, тому що edце стандартний текстовий редактор.
десерт

5
@ubashu Хоча це не grepвідповідь, відповідь "Ви не можете зробити це з X, але ви можете це зробити з Y, ось як" все ще є вірною відповіддю, оскільки ви не тільки відповідаєте на запитання ОП, але й надаєте альтернативу це спрацювало б. Тут є правильним типом відповіді.
Томас Уорд

5
awk '/match/{system("sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME)}' infile

Тут ми використовуємо AWK «s функцію для виклику зовнішньої команди для друку лінії , які AWK збіглися з малюнком з 5 - й лінії до і після матчу.system(command)sedmatch

Синтаксис простий, вам просто потрібно помістити саму зовнішню команду всередину подвійної цитати, а також її комутатори та вийти з речей, які ви хочете точно передати команді, все інше, що стосується awkсамих параметрів, повинно бути поза цитатами. Тому нижче СЕД :

"sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME

перекласти на:

sed -n "NR-5p; NRp; NR+5p" FILENAME

NR- номер рядка, який збігається з шаблоном matchі FILENAMEє поточним іменем файлу обробки, що проходить повз awk.


2

використовуючи текстовий файл прикладу @ glenn та використовуючи perl замість awk:

$ perl -n0E 'say /(.*\n)(?=(?:.*\n){4}(.*match.*\n)(?:.*\n){4}(.*\n))/g' ex

дасть ті самі результати, але працює швидше:

a
f match
k
d
i match
n

Жоао, ви з'являєтесь у черзі на огляд LQ, а @waltinator проголосував за видалення, тому наступного разу будьте трохи більш багатослівним ... ;-) Також +1, щоб вийти з черги LQ ... : P
Фабі

1
@JJoao Черга на огляд низької якості. Ваша відповідь, ймовірно, знайшла там, бо це був 90% код.
wjandrea

1
@JJoao 90% - це лише мій спосіб пояснення. Я не знаю, що насправді використовується евристикою.
wjandrea

1
Кафе Menos, mais escrita! @JJoao : D ;-): D
Fabby

1
@Fabby: Sem café nada funciona: D - ймовірно, це відображатиметься в LCQ (= низька черга на каву)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.