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
Fooi Barbędzie obejmować całą linię.
Ze sedskryptem:
#!/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
printfTutaj 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 spacei hold space TUTAJ .
grymoire.com ma naprawdę dobre rzeczy na temat shellprogramowania.
h, n, H, x, p, qznaczy 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 greptylko, możesz zbudować następujący potok:
grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'
Pierwszy greppobierze wszystkie linie, które zawierają, Fooa także linię po meczu. Następnie otrzymujemy linie, które zawierają, Barjak 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 grepna funkcjonalność zorientowaną na linię, każde rozwiązanie z tym rozwiązaniem może być „włamaniem” i prawdopodobnie lepiej jest użyć czegoś, pcregrepco 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:
-owydrukuj tylko pasującą część. Konieczne, ponieważ dołączenie -zspowoduje 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 ./filenamezamiast filenameawk)