여러 AND 패턴으로 grep을 실행하는 방법은 무엇입니까?


86

다중 패턴을 암시 적 AND 패턴 사이에서 일치 시키려고합니다. 즉, 여러 greps를 순서대로 실행하는 것과 같습니다.

grep pattern1 | grep pattern2 | ...

어떻게 그것을 같은 것으로 변환합니까?

grep pattern1 & pattern2 & pattern3

인수를 동적으로 작성하기 때문에 단일 grep을 사용하고 싶습니다. 따라서 모든 것이 하나의 문자열에 맞아야합니다. 필터를 사용하는 것은 grep이 아닌 시스템 기능이므로 이에 대한 인수가 아닙니다.


이 질문을 다음과 혼동하지 마십시오.

grep "pattern1\|pattern2\|..."

이것은 OR 다중 패턴 일치입니다.



SO에 대한 비슷한 질문 : 파일에 여러 문자열 또는
— 정규식

답변:


78

agrep 이 구문으로 할 수 있습니다 :

agrep 'pattern1;pattern2'

GNU를 사용 grep하여 PCRE 지원으로 빌드하면 다음을 수행 할 수 있습니다.

grep -P '^(?=.*pattern1)(?=.*pattern2)'

와 ASTgrep :

grep -X '.*pattern1.*&.*pattern2.*'

(추가 .*의은으로 <x>&<y>모두 일치하는 문자열과 일치 <x>하고 <y> 정확하게 , a&b수있는 그런 캐릭터가 없다으로 일치 절대 수 를 모두 a와 b동시에 참조).

패턴이 겹치지 않으면 다음 작업을 수행 할 수도 있습니다.

grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'

가장 좋은 휴대용 방법은 awk이미 언급 한 바와 같습니다.

awk '/pattern1/ && /pattern2/'

로 sed:

sed -e '/pattern1/!d' -e '/pattern2/!d'

모든 정규 표현식 구문이 다르므로주의하십시오.


1
agrep구문은 어떤 버전이 도입되었다 ... 나를 위해 작동하지 않습니다?
— 라만

1992 년의 @Raman 2.04는 이미 그것을 가지고있었습니다. 나는 그것이 처음부터 존재하지 않았다고 믿을 이유가 없다. 최신 (1992 년 이후) 버전은 glimpse / webglimpse에agrep 포함되어 있습니다 . 아마도 당신은 다른 구현을 가지고있을 것입니다. 나는 ast-grep 버전에 실수가 있었지만, 정규 표현식 의 옵션 은 아닙니다 . -X-A
— Stéphane Chazelas

@ StéphaneChazelas 고마워, agrepFedora 23에 0.8.0이 있습니다. 이것은 agrep당신이 참조 하는 것과 다릅니다 .
— Raman

1
@Raman, 당신은 TREagrep 같은 소리 .
— Stéphane Chazelas

2
@Techiee 또는 그냥awk '/p1/ && /p2/ {n++}; END {print 0+n}'
— Stéphane Chazelas

19

grep 버전을 지정하지 않았습니다. 이것은 중요합니다. 일부 정규식 엔진은 '&'를 사용하여 AND로 그룹화하여 여러 개의 일치 항목을 허용하지만 이는 비표준적이고 이식 불가능한 기능입니다. 그러나 적어도 GNU grep은 이것을 지원하지 않습니다.

OTOH는 grep을 sed, awk, perl 등으로 간단히 바꿀 수 있습니다 (체중 증가 순서로 나열). awk를 사용하면 명령은 다음과 같습니다.

awk '/ regexp1 / && / regexp2 / && / regexp3 / {인쇄; } '

명령 행에 쉽게 지정되도록 구성 할 수 있습니다.


3
평범한 BRE와 달리 awkERE 를 사용 한다는 것을 기억하십시오 . grep -Egrep
— jw013

3
awk의 정규식을 ERE 라고 하지만 실제로는 조금 특이합니다. 다음은 아마도 누구보다 더 자세한 정보 일 것입니다 : wiki.alpinelinux.org/wiki/Regex
— dubiousjim

grep 2.7.3 (openSUSE)에게 감사합니다. 나는 당신을 옹호했지만, 나는 잠시 동안 질문을 계속할 것 awk입니다.
— greenoldman

2
기본 동작은 일치하는 줄을 인쇄하여 { print; }부분이 실제로 필요하지 않거나 유용하지 않은 것입니다.
— tripleee

7

patterns한 줄에 하나의 패턴 이 포함되어 있으면 다음과 같이 할 수 있습니다.

awk 'NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1' patterns -

또는 정규 표현식 대신 하위 문자열과 일치합니다.

awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns -

대신 경우 입력없이 라인의 모든 인쇄하려면 patterns비어를 대체 NR==FNR와 함께 FILENAME==ARGV[1], 또는에 ARGIND==1에 gawk.

이 함수는 인수로 지정된 각 문자열을 하위 문자열로 포함하는 STDIN 행을 인쇄합니다. gagrep all을 나타내며 gai대소 문자를 무시합니다.

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 "$@") -; }

7

이것은 좋은 해결책은 아니지만 다소 멋진 "속임수"를 보여줍니다.

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

1
사용 중 chained-grep()또는 function chained-grep아니지만 function chained-grep(): unix.stackexchange.com/questions/73750/...
— nisetama

3

git grep

부울 표현식을 사용 git grep하여 여러 패턴을 결합 하는 구문은 다음과 같습니다 .

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3

위의 명령은 한 번에 모든 패턴과 일치하는 줄을 인쇄합니다.

--no-index Git에서 관리하지 않는 현재 디렉토리에서 파일을 검색하십시오.

확인 man git-grep도움.

또한보십시오:

들어 OR 연산을 참조하십시오


1

ripgrep

다음은 다음을 사용하는 예입니다 rg.

rg -N '(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)' file.txt

유한 자동 마타, SIMD 및 공격적인 리터럴 최적화를 사용하여 검색을 매우 빠르게 수행하는 Rust의 정규식 엔진 위에 구축되어 있기 때문에 가장 빠른 그 리핑 도구 중 하나입니다 .

GH-875의 관련 기능 요청도 참조하십시오 .


1

여기에 내가 취하는 것이 있으며 이것은 여러 줄의 단어에 적용됩니다.

사용하십시오 find . -type f많은 다음에
-exec grep -q 'first_word' {} \;
마지막 키워드
-exec grep -l 'nth_word' {} \;

-q
-l일치 하는 자동 / 무음 쇼 파일

다음은 단어 'rabbit'및 'hole'이 포함 된 파일 이름 목록을 반환합니다.
find . -type f -exec grep -q 'rabbit' {} \; -exec grep -l 'hole' {} \;


-2

모든 단어 (또는 패턴)를 찾으려면 FOR loop에서 grep을 실행할 수 있습니다 . 여기서 가장 큰 장점 은 regexs 목록 에서 검색하는 것 입니다.

실제 예를 들어 내 대답을 편집하십시오 .

# 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

이제이 파일에서 실행 해 봅시다 :

으 아아아

아아아 아아아

bb

아바바 바바

ccccccc

dsfsdf

bbbb

cccdd

aa

카아

# ./search_all_regex_and_error_if_missing.sh

aaaaaaa aa

^ a + $가 파일에서 발견되었습니다.

bbbbbbbbb bbbb

^ b + $가 파일에 있습니다.

으 아아아

^ h + $가 파일에서 발견되었습니다.

오류 : 파일에서 ^ d + $를 찾을 수 없습니다. 종료!


1
논리가 잘못되었습니다. ALL운영자 에게 요청했지만 코드는 OR운영자가 아닌 연산자로 작동합니다 AND. 그리고 btw. 그 ( OR)가 질문에 바로 주어진 훨씬 쉬운 해결책입니다.
— greenoldman

@greenoldman 논리는 간단하다 : for는 목록 에있는 모든 단어 / 패턴 을 반복하며 , 파일에서 발견되면 인쇄한다. 따라서 단어를 찾을 수없는 경우 조치가 필요하지 않으면 다른 것을 제거하십시오.
— 노암 마 노스

1
나는 당신의 논리뿐만 아니라 내 질문을 이해 - 나는에 대해 질문했다 AND가 패턴 A와 패턴 B와 패턴 C와 일치하는 경우에만 긍정적 인 히트 파일을 의미 운영자 ... AND이 일치하는 경우에 경우 파일은 긍정적 인 히트 패턴 A 또는 패턴 B 또는 ... 지금 차이가 보입니까?
— greenoldman

@greenoldman 왜이 루프가 모든 패턴에 대해 AND 조건을 검사하지 않는다고 생각하는지 모르십니까? 그래서 실제 예제를 사용하여 답변을 편집했습니다. 파일의 모든 정규 표현식을 파일에서 검색하고 누락 된 첫 번째 정규 표현식에서 오류와 함께 종료됩니다.
— 노암 마 노스

당신은 당신의 눈앞에 그것을 가지고, 당신은 첫 경기가 실행 된 직후 긍정적 인 경기를합니다. 모든 결과를 "수집"하고 계산 AND해야합니다. 그런 다음 여러 파일에서 실행되도록 스크립트를 다시 작성해야합니다. 질문에 이미 답변되어 있고 시도해도 테이블에 아무것도 표시되지 않습니다. 죄송합니다.
— greenoldman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.