여러 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수있는 그런 캐릭터가 없다으로 일치 절대 를 모두 ab동시에 참조).

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

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==1gawk.

이 함수는 인수로 지정된 각 문자열을 하위 문자열로 포함하는 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.