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ć innym agrep 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. odpowiednik grep -E, w przeciwieństwie do BRE ', których używa zwykły grep.
  • 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 "[email protected]") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "[email protected]") -; }  

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 "[email protected]" } 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() lub function chained-grep, ale nie function 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:

Aby zapoznać się z operacją OR , zobacz:

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 nie AND. 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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *