Chciałbym uzyskać dopasowanie do wielu wzorców z niejawnym AND między wzorcami, tj. równoważne uruchomieniu kilku grepsów w sekwencji:
grep pattern1 | grep pattern2 | ...
Jak więc przekonwertować to na coś takiego?
grep pattern1 & pattern2 & pattern3
Chciałbym użyć pojedynczego grepa, ponieważ buduję argumenty dynamicznie, więc wszystko musi pasować do jednego ciągu. Korzystanie z filtra jest funkcją systemu, a nie grep, więc nie jest to argument za tym.
Nie myl tego pytania z:
grep "pattern1\|pattern2\|..."
To jest LUB dopasowanie do wielu wzorców.
Komentarze
Odpowiedź
agrep
może to zrobić za pomocą następującej składni:
agrep "pattern1;pattern2"
Z GNU grep
, po zbudowaniu w Dzięki obsłudze PCRE możesz:
grep -P "^(?=.*pattern1)(?=.*pattern2)"
Z ast grep
:
grep -X ".*pattern1.*&.*pattern2.*"
(dodanie .*
s jako <x>&<y>
pasuje do ciągów pasujących zarówno do <x>
, jak i <y>
dokładnie , nigdy by nie pasowało, ponieważ nie ma takiego ciągu, który mógłby być zarówno a
, jak i b
w tym samym czasie).
Jeśli wzorce się nie nakładają, możesz również:
grep -e "pattern1.*pattern2" -e "pattern2.*pattern1"
Najlepszym przenośnym sposobem jest prawdopodobnie awk
, jak już wspomniano:
awk "/pattern1/ && /pattern2/"
sed
:
sed -e "/pattern1/!d" -e "/pattern2/!d"
Pamiętaj, że wszystkie będą miały inną składnię wyrażeń regularnych.
Komentarze
- Składnia
agrep
nie działa dla ja … w której wersji został wprowadzony? - @Raman 2.04 z 1992 roku już go miał. Nie ' nie mam powodu, by sądzić, że od początku nie było go '. Nowsze (po 1992) wersje
agrep
można znaleźć w glimpse / webglimpse . Być może masz inną implementację. Jednak popełniłem błąd w wersji ast-grep, opcja dla rozszerzonych wyrażeń regularnych to-X
, a nie-A
. - @St é phaneChazelas Dzięki, mam
agrep
0.8.0 w Fedorze 23. Wygląda na to, że być innymagrep
niż ten, do którego się odnosisz. - @Raman, twój brzmi jak TRE
agrep
. - @Techiee lub po prostu
awk '/p1/ && /p2/ {n++}; END {print 0+n}'
Odpowiedź
Nie określono wersji grep, to ważne. Niektóre mechanizmy wyrażeń regularnych pozwalają na wielokrotne dopasowywanie grupowane według ORAZ za pomocą „& „ale to jest niestandardowa i nieprzenośna funkcja. Ale przynajmniej GNU grep tego nie obsługuje.
OTOH możesz po prostu zamienić grep na sed, awk, perl itp. . (wymienione w kolejności wzrostu masy ciała). W awk polecenie wyglądałoby tak, jak
awk "/regexp1/ && /regexp2/ && /regexp3/ { print; }"
i można je w łatwy sposób skonstruować tak, aby było podane w wierszu poleceń.
Komentarze
- Pamiętaj tylko, że
awk
używa ERE ', np. odpowiednikgrep -E
, w przeciwieństwie do BRE ', których używa zwykłygrep
. -
awk
' wyrażenia regularne są nazywane ERE, ale w rzeczywistości ' są trochę dziwaczne. Oto prawdopodobnie więcej szczegółów, niż ktokolwiek dba o: wiki.alpinelinux.org/wiki/Regex - Dziękuję, grep 2.7.3 ( openSUSE). Głosowałem za tobą, ale przez chwilę pozostawiam otwarte pytanie, może jest jakaś sztuczka dla grepa (nie to, że nie lubię
awk
– po prostu wiedzieć, że więcej znaczy lepiej). - Domyślną akcją jest wydrukowanie pasującego wiersza, więc
{ print; }
część nie jest ' naprawdę potrzebna lub przydatna w tym miejscu.
Odpowiedź
Jeśli patterns
zawiera po jednym wzorcu w każdym wierszu, możesz zrobić coś takiego:
awk "NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1" patterns -
Lub to dopasowuje podciągi zamiast zwykłych wyrażenia:
awk "NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1" patterns -
Aby wydrukować wszystko zamiast żadnych wierszy wejścia w jeśli patterns
jest pusty, zamień NR==FNR
na FILENAME==ARGV[1]
lub na ARGIND==1
w gawk
.
Te funkcje wyświetlają wiersze STDIN, które zawierają każdy ciąg określony jako argument jako podłańcuch. ga
oznacza grep all i gai
ignoruje wielkość liter.
ga(){ awk "FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1" <(printf %s\\n "$@") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "$@") -; }
Komentarze
- trafna odpowiedź, która odnosi się do kilku zastosowań i działa (zweryfikowana na macOS)
Odpowiedź
grep pattern1 | grep pattern2 | ...
Chciałbym użyć pojedynczego grepa, ponieważ buduję argumenty dynamicznie , więc wszystko musi zmieścić się w jednym ciągu
Potok można zbudować dynamicznie (bez uciekania się do eval
):
# Executes: grep "$1" | grep "$2" | grep "$3" | ... function chained-grep { local pattern="$1" if [[ -z "$pattern" ]]; then cat return fi shift grep -- "$pattern" | chained-grep "$@" } cat something | chained-grep all patterns must match order but matter dont
Prawdopodobnie nie jest to jednak bardzo wydajne rozwiązanie.
Komentarze
- Użyj
chained-grep()
lubfunction chained-grep
, ale niefunction chained-grep()
: unix.stackexchange.com/questions/73750/… - Czy możesz opisać, na czym polega sztuczka? Czy możesz dodać go do odpowiedzi ( bez ” Edycja: „, ” Aktualizacja: ” lub podobna) przez edycję ?
- Przeformułowano odpowiedź, aby sztuczka była jaśniejsza (np .: dynamiczne zbudowanie potoku powłoki)
Odpowiedź
git grep
Oto składnia używająca git grep
łączenie wielu wzorców za pomocą wyrażeń logicznych :
git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3
Powyższe polecenie wydrukuje wiersze pasujące do wszystkich wzorców naraz.
--no-index
Wyszukaj pliki w bieżącym katalogu, który nie jest zarządzany przez Git.
Zaznacz man git-grep
, aby uzyskać pomoc.
Zobacz także:
- Jak do nas e grep do dopasowania string1 AND string2?
- Sprawdź, czy wszystkie ciągi lub wyrażenia regularne istnieją w pliku .
Aby zapoznać się z operacją OR , zobacz:
- Jak wykonać grep dla wielu wzorce ze wzorem zawierającym pionową kreskę?
- Grep: jak dodać ” LUB ” warunek?
Komentarze
- Doskonała odpowiedź. Dziękuję.
Odpowiedź
Oto moja opinia, która działa dla słów w wielu wierszach:
Użyj find . -type f
, a po nim tyle
-exec grep -q "first_word" {} \;
i ostatniego słowa kluczowego z
-exec grep -l "nth_word" {} \;
-q
cicho / cicho
-l
pokaż pliki z dopasowaniami
Poniższa lista zwraca nazwy plików ze słowami „rabbit” i „hole”:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;
Komentarze
- Jeśli przyjrzysz się uważnie, może się okazać, że nie jest to funkcja, o którą prosi się pytanie.
Odpowiedź
ripgrep
Oto przykład z użyciem rg
:
rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt
Jest to jedno z najszybszych narzędzi do grepowania, ponieważ opiera się na Silnik wyrażeń regularnych Rusta , który wykorzystuje automaty skończone, SIMD i agresywne optymalizacje literałów, aby bardzo przyspieszyć wyszukiwanie.
Zobacz także powiązane żądania funkcji pod adresem GH-875 .
Odpowiedź
Aby znaleźć wszystkie słowa (lub wzorce), możesz uruchomić grep
w pętli for
. Główną zaletą jest tutaj wyszukiwanie na liście wyrażeń regularnych .
Prawdziwy przykład:
# File "search_all_regex_and_error_if_missing.sh" find_list="\ ^a+$ \ ^b+$ \ ^h+$ \ ^d+$ \ " for item in $find_list; do if grep -E "$item" file_to_search_within.txt then echo "$item found in file." else echo "Error: $item not found in file. Exiting!" exit 1 fi done
Teraz uruchommy go na tym pliku:
hhhhhhhhhh aaaaaaa bbbbbbbbb ababbabaabbaaa ccccccc dsfsdf bbbb cccdd aa caa
$ ./search_all_regex_and_error_if_missing.sh aaaaaaa aa ^a+$ found in file. bbbbbbbbb bbbb ^b+$ found in file. hhhhhhhhhh ^h+$ found in file. Error: ^d+$ not found in file. Exiting!
Komentarze
- Twoja logika jest błędna – prosiłem o , Twój kod działa jako operator
OR
, a nieAND
. A przy okazji (OR
) jest dużo łatwiejszym rozwiązaniem, biorąc pod uwagę pytanie. - @greenoldman Logika jest prosta: pętla for będzie pętla na WSZYSTKICH słowach / wzorach na liście, a jeśli zostanie znaleziony w pliku – wydrukuje go. Po prostu usuń pozostałe, jeśli ' nie potrzebujesz działania w przypadku, gdy słowo nie zostało znalezione.
- Rozumiem twoją logikę i moje pytanie – pytałem o operator
AND
, co oznacza, że plik jest trafieniem pozytywnym tylko wtedy, gdy pasuje do wzorca A i wzorca B i wzór C i …AND
W przypadku, gdy plik jest trafiony, jeśli tak tches wzór A lub wzór B lub … Czy widzisz teraz różnicę? - @greenoldman nie wiesz, dlaczego myślisz, że ta pętla nie sprawdza warunku AND dla wszystkich wzorców? Więc ' zredagowałem moją odpowiedź na prawdziwym przykładzie: wyszuka w pliku wszystkie wyrażenia regularne z listy, a na pierwszym, którego brakuje – zakończy się z błędem.
- Masz to tuż przed oczami, masz pozytywne dopasowanie zaraz po wykonaniu pierwszego dopasowania. Powinieneś mieć ” zebrać ” wszystkie wyniki i obliczyć na nich
AND
. Następnie powinieneś przepisać skrypt tak, aby działał na wielu plikach – wtedy być może zdasz sobie sprawę, że na pytanie jest już odpowiedź, a twoja próba nie wnosi nic do tabeli, przepraszam.
foo
i wiersze zawierającebar
” zobacz używanie grep dla wielu wzorców wyszukiwania