Jak mogę grepować katalog dla linii zawierających „Foo”, ale dopasowywać tylko, gdy następny wiersz zawiera również „Bar”?
Jak mogę grepować katalog dla linii zawierających „Foo”, ale dopasowywać tylko, gdy następny wiersz zawiera również „Bar”?
Odpowiedzi:
@ warl0ck wskazał mi właściwy kierunek pcregrep
, ale powiedziałem: „zawiera”, a nie „jest” i zapytałem o katalog, a nie plik.
Wydaje mi się, że to działa.
pcregrep -rMi 'Foo(.*)\n(.*)Bar' .
Wydaje się, że sam Grep go nie obsługuje, zamiast tego użyj pcregrep:
Foo
Bar
Foo
abc
pcregrep -M "Foo\nBar" file
Dostał:
Foo
Bar
Foo
i Bar
będzie obejmować całą linię.
Ze sed
skryptem:
#!/bin/sed -nf
/^Foo/{
h # put the matching line in the hold buffer
n # going to nextline
/^Bar/{ # matching pattern in newline
H # add the line to the hold buffer
x # return the entire paragraph into the pattern space
p # print the pattern space
q # quit the script now
}
}
Aby go użyć:
chmod +x script.sed
printf '%s\n' * | ./script.sed
printf
Tutaj zobaczyć wszystkie pliki w bieżącym katalogu w jednym wierszu każdego, i przekazać je sed
.
Uwaga : jest to posortowane według kolejności alfabetycznej.
Więcej informacji przydatnych pattern space
i hold space
TUTAJ .
grymoire.com ma naprawdę dobre rzeczy na temat shell
programowania.
h, n, H, x, p, q
znaczy Bardzo interesujące.
pattern space
& hold space
: grymoire.com/Unix/Sed.html#uh-56 lub francuskim commentcamarche.net/faq/9536-sed-introduction-a-sed-part-i
Używając grep
tylko, możesz zbudować następujący potok:
grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'
Pierwszy grep
pobierze wszystkie linie, które zawierają, Foo
a także linię po meczu. Następnie otrzymujemy linie, które zawierają, Bar
jak również linię przed dopasowaniem, i na koniec wyodrębniamy linie z tego wyjścia, które zawierają Foo
.
EDYCJA: Jak wskazano manatwork , istnieją pewne problematyczne przypadki, których należy przestrzegać. Chociaż jest to interesujące wyzwanie, z uwagi grep
na funkcjonalność zorientowaną na linię, każde rozwiązanie z tym rozwiązaniem może być „włamaniem” i prawdopodobnie lepiej jest użyć czegoś, pcregrep
co bardziej pasuje do danego zadania.
find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar'
Chociaż wolę używać rozwiązania Nathana pcregrep
, oto rozwiązanie wykorzystujące tylko grep
grep -o -z -P 'Foo(.*)\n(.*)Bar' file
Objaśnienie opcji:
-o
wydrukuj tylko pasującą część. Konieczne, ponieważ dołączenie -z
spowoduje wydrukowanie całego pliku (chyba że gdzieś jest \ 0)-z
Traktuj dane wejściowe jako zestaw wierszy zakończonych zerowym bajtem (znak NUL ASCII) zamiast nowego wiersza.-P
składnia wyrażeń regularnych perl EDYCJA: Ta wersja drukuje całe dopasowane linie
grep -o -P -z '(.*)Foo(.*)\n(.*)Bar(.*)' file
-z
. Niektóre „(. *)” Przed i po całym wyrażeniu spowodowałyby, że wypisałby całe dopasowane linie. Na razie podciągi przed „Foo” i po „Bar” nie są wyświetlane.
Z awk:
awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
/foo/ {prev=$0; next}
{prev=""}' file1...
(ogólna uwaga na temat ograniczenia awk: uwaga, że jeśli niektóre nazwy plików mogą zawierać znaki „=”, musisz przekazać je jako ./filename
zamiast filename
awk)