grep zwraca linie N-ty i M-ty przed i po meczu

12

Wiem, że dzięki grep mogę używać pól -Ai -Bwyciągać poprzednie i następne wiersze z meczu.

Wciągają jednak wszystkie linie między dopasowaniami w zależności od liczby określonych linii.

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

Chciałbym otrzymać tylko te 5 th linię przed meczem i 5 th wiersz po meczu oprócz dopasowanej linii i nie dostać się granice pomiędzy.

Czy jest na to sposób grep?

chollida
źródło
1
Możesz to zrobić, wpuszczając go do sed. Właśnie to przetestowałem i zadziałało, ale zadziałało tylko wtedy, gdy w pliku było 1 dokładne dopasowanie: grep -r -i -B 5 -A 5 "match" | sed -e 1b -e '$!d'
Terrance
@Terrance dzięki za sugestię, jak wspomniałeś, ponieważ zbieram 1000 linii, to nie zadziała.
chollida
Nie sądzę, żeby grep zadziałał sam ... Pracuję nad skryptem dla ciebie
Joshua Besneatte
Nie ma problemu! Trochę zainteresowany zobaczeniem, jakie odpowiedzi otrzymujesz. =)
Terrance
czy to jest w jednym pliku czy w wielu plikach?
Joshua Besneatte,

Odpowiedzi:

1

Narzędzie, którego chcesz użyć, nazywa się sift. Jest to w zasadzie grep na sterydach. Grep równolegle. Sift ma ogromną liczbę opcji, aby zrobić dokładnie to, co chcesz - w szczególności zwrócić konkretną linię względem dopasowania (-ów), po których może / może nie następować / poprzedzony jakimś tekstem.

Dziwi mnie, że sift nie jest głównym nurtem GNU, ponieważ został napisany w języku go, ale instaluje się w systemie Linux w porządku. IT wyszukuje równolegle, używając wszystkich ogromnych ilości tekstu, gdzie grep zajmuje to samo tygodnie.

Sift website - patrz przykłady

Brandon Haberfeld
źródło
Witamy w AskUbuntu, dziękuję za odpowiedź. Musisz podać przykład CLI, który może rozwiązać ten konkretny problem, a nie link do odsiewanej strony internetowej. To jest koniec pytania i odpowiedzi, dzięki.
Bernard Wei,
12

Gdyby:

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

Następnie:

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
Glenn Jackman
źródło
+1, ale czy mógłbyś wyjaśnić semantykę /match/ {matched[NR]}? Nigdy nie widziałem tablicy ani zmiennej jako całego polecenia. Czy umieszcza bieżący numer rekordu każdej dopasowanej linii w tablicy?
Joe
Jest to dziwna dziwność: jeśli odwołujesz się do elementu tablicy bez przypisania, ten klucz jest dodawany do tablicy (bez wartości). Następnie ten klucz pojawia się w wyrażeniu key in array. Pamiętam numery linii, w których pojawia się wzór
glenn jackman
6

Jest to w zasadzie rozwiązanie Glenna, ale zaimplementowane z Bash, Grep i sed.

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

Zauważ, że numery linii mniejsze niż 1 spowodują błąd sed, a numery linii większe niż liczba linii w pliku sprawią, że nic nie wydrukuje.

To tylko absolutne minimum. Aby działało rekurencyjnie i obsługiwało przypadki powyższych numerów linii, zajęłoby trochę czasu.

wjandrea
źródło
6

Tego nie da się zrobić tylko grep. Jeśli edjest to opcja:

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

Skrypt w zasadzie mówi: dla każdego dopasowania / match /, wypisz wiersz 5 linii wcześniej, potem 5 linii później, a następnie 5 linii później.

JoL
źródło
5
@ubashu Czy sądzisz, że będzie bardziej pomocne OP, dając proste mieszkanie „nie da się tego zrobić grep”? Dostarczam coś, co uważam za dobrą alternatywę dla rozwiązania problemu OP. Z Centrum pomocy: „Czego konkretnie dotyczy pytanie? Upewnij się, że twoja odpowiedź stanowi - lub realną alternatywę. Odpowiedź może brzmieć„ nie rób tego ”, ale powinna również zawierać„ spróbuj tego ” . ”
JoL
edjest zawsze odpowiedzią, ponieważ edjest standardowym edytorem tekstu.
deser
5
@ubashu Chociaż to nie jest grepodpowiedź, odpowiedź „Nie możesz tego zrobić za pomocą X, ale możesz to zrobić za pomocą Y, oto jak” nadal jest poprawną odpowiedzią, ponieważ nie tylko odpowiadasz na pytanie OP, ale także stanowisz alternatywę to powinno działać. To jest poprawny typ odpowiedzi tutaj.
Thomas Ward
5
awk '/match/{system("sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME)}' infile

Tutaj używamy awk „s funkcję zadzwonić zewnętrznego polecenia, aby wydrukować linie, które awk dopasowane wzorkiem z 5 th linii przed i po meczu.system(command)sedmatch

Składnia jest łatwa, wystarczy umieścić zewnętrzne polecenie w cudzysłowie, a także jego przełączniki i uciec od tego, co chcesz dokładnie przekazać do polecenia, wszystko inne związane z awksamymi opcjami powinno znajdować się poza cudzysłowami. Więc poniżej sed :

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

Przetłumacz na:

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

NRjest liczbą linii, która pasuje do wzorca matchi FILENAMEjest przetwarzanie prądu nazwa pliku Mijając awk.

αғsнιη
źródło
2

używając przykładowego pliku tekstowego @ glenn i używając perla zamiast awk:

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

da te same wyniki, ale działa szybciej:

a
f match
k
d
i match
n
Fabby
źródło
João, pojawiasz się w kolejce recenzji LQ, a @waltinator głosował za usunięciem, więc następnym razem bądź trochę bardziej gadatliwy ... ;-) Również +1, aby wydostać się z kolejki LQ ... : P
Fabby
1
@JJoao Kolejka przeglądu niskiej jakości. Twoja odpowiedź prawdopodobnie została tam znaleziona, ponieważ był to kod 90%.
wjandrea
1
@JJoao 90% to mój sposób na wyjaśnienie tego. Nie wiem, jakie heurystyki są faktycznie używane.
wjandrea
1
Menos café, mais escrita! @JJoao : D ;-): D
Fabby
1
@Fabby: Sem café nada funciona: D - prawdopodobnie pojawiłby się w LCQ (= kolejka niskiej kawy)