grep으로 한 줄에 두 줄을 일치시킵니다.


218

grep두 개의 다른 문자열이 포함 된 줄을 일치시키는 데 사용하려고합니다 . 나는 다음을 시도했지만 이것은 내가 원하는 것이 아닌 string1 또는 string2 를 포함하는 줄과 일치합니다 .

grep 'string1\|string2' filename

그렇다면 두 문자열을 모두grep 포함하는 줄 과 어떻게 일치 합니까?


답변:


189

당신이 사용할 수있는 grep 'string1' filename | grep 'string2'

또는, grep 'string1.*string2\|string2.*string1' filename


5
이 받아 들여졌다 이상한 있도록 @AlexanderN 참으로 나는, 여러 줄에 그게 전부 작동하도록 어차피 ..
물병 전원

1
여러 줄로 된 질문이 아니 었습니다. 그것은 여러 줄을한다면, GREP -P는 ... 펄 스타일의 정규식을 지원합니다
스콧 Prive

20
'string1'과 'string2'가 같은 줄에있을 때만 작동합니다. 'string1'또는 'string2'가있는 행을 찾으려면 user45949의 답변을 참조하십시오.
lifeson106

10
첫 번째 옵션 : 하나의 grep을 두 번째로 파이핑해도 OR 결과가 생성되지 않으며 AND 결과가 생성됩니다.
masukomi

1
내가 사용grep -e "string1" -e "string2"
Ravi Dhoriya ツ

198

나는 이것이 당신이 찾고있는 것이라고 생각합니다.

grep -E "string1|string2" filename

나는 다음과 같이 대답한다고 생각합니다.

grep 'string1.*string2\|string2.*string1' filename

둘 중 하나만 존재하거나 둘 다 존재하지 않는 경우에만 일치합니다.


14
않을 것 grep -e "string1" -e "string2" filename같은 행동을 할?
janosdivenyi

25
이것은 string1 또는 string2를 grep하는 방법입니다. 질문은 분명히 그들이 string1과 string2를 찾고 있다고 말합니다.
orion elenzil

9
질문이 매우 정확하다는 것을 확신하십시오.How do I match lines that contains *both* strings?
r0estir0bbe

같은 줄로 인쇄 할 수 있습니까?
吴毅 凡

1
이 답변이 여전히 여기에있는 이유는 무엇입니까? 질문에 대한 답변이 아닙니다.
Prometheus

26

모든 단어를 포함하는 파일을 임의의 순서로 검색하려면

grep -ril \'action\' | xargs grep -il \'model\' | xargs grep -il \'view_type\'

첫 번째 grep은 재귀 적 검색 ( r)을 시작하고 대소 문자 ( i)를 무시 하고 파일의 어느 곳에서든 l한 용어 ( 'action'작은 따옴표)와 일치하는 ( ) 파일 이름을 나열 (인쇄) 합니다.

후속 greps는 다른 용어를 검색하여 대소 문자를 구분하지 않고 일치하는 파일을 나열합니다.

최종 파일 목록은 파일의 임의의 위치에 상관없이 이러한 용어가 포함 된 파일입니다.


2
동의했다! 공백이있는 파일 이름을 처리하기 위해 xargs에 "-d '\ n'"을 지정해야한다는 점에 주목할 것입니다. 이것은 Linux에서 나를 위해 일했습니다 : grep -ril 'foo' | xargs -d '\n' grep -il 'bar'
Tommy Harris

16

당신이있는 경우 grep로모그래퍼 -P제한에 대한 옵션 perl정규식, 당신은 사용할 수 있습니다

grep -P '(?=.*string1)(?=.*string2)'

겹치는 문자열로 작업 할 수 있다는 이점이 있습니다. and를 더 직접 지정할 수 있기 때문에 perlas를 사용 하는 것이 다소 간단 grep합니다.

perl -ne 'print if /string1/ && /string2/'

1
가장 좋은 답변입니다. Shell은 매우 쉽고 빠르지 만 패턴이 복잡해지면 Python 또는 Perl (또는 Awk)을 사용해야합니다. 순수한 껍질로 할 수 있음을 증명하기 위해 벽에 머리를 두르지 마십시오 (요즘 의미하는 것). 이 도구는 기존 쉘 스크립트에 dibble을 포함하는 "한 줄짜리"구문으로 사용할 수 있습니다.
Scott Prive

12

귀하의 방법은 거의 좋았으며 -w 만 누락되었습니다.

grep -w 'string1\|string2' filename

1
적어도 OS-X 및 FreeBSD에서는 작동합니다! 내 생각 엔 당신이 다른 것에 있다고 생각합니다 (OP가 정의하지 않은 것-당신을 제외하고 많은 사용자에게 정답을 내리지 않기를 바랍니다).
Leo

OS-X에 있습니다. 아마도 내가 올바르게하고 있지 않습니까? 내가 한 일을 살펴보십시오 : i.imgur.com/PFVlVAG.png
Ariel

1
이상한. 차이점이 파일에 그 리핑되지 않았을 것으로 예상했지만 ls로 메소드를 파이프하면 다음과 같은 결과를 얻지 못합니다. imgur.com/8eTt3Ak.png- 둘 다 OS-X 10.9.5 ( "grep (BSD grep) 2.5.1-FreeBSD") 및 FreeBSD 10 ( "grep (GNU grep) 2.5.1-FreeBSD"). 당신이 무엇인지 궁금합니다 grep -V.
Leo

1
귀하의 예는 저에게 효과적 입니다. 하위 문자열을 검색하려면 grep 내에 정규 표현식을 구성해야한다고 생각합니다. 이런 식으로 뭔가 :grep -w 'regexp1\|regexp2' filename
아리엘

2
OP는 string1 또는 string2 를 일치시켜 예제를 표시하고 문자열을 모두 포함 하는 행을 일치시키는 방법을 묻습니다 . 이 예제는 여전히 OR을 생성합니다.
gustafbstrom

7

|정규 표현식 의 연산자는 또는을 의미합니다. 즉, string1 또는 string2가 일치한다고합니다. 당신은 할 수 있습니다 :

grep 'string1' filename | grep 'string2'

첫 번째 명령의 결과를 두 번째 grep으로 파이프합니다. 그것은 둘 다 일치하는 줄만 줄 것입니다.


1
귀하의 진술은 사실이지만 OP 질문에 대답하지 마십시오
Ben Wheeler

이것은 질문에 대한 답변이며 실제로 대부분의 사람들이 질문을 쓰는 방식입니다.
Peter K

7

다음과 같이 시도해보십시오.

(pattern1.*pattern2|pattern2.*pattern1)

4

사람들이 펄과 파이썬, 복잡한 셸 스크립트를 제안한 것처럼 간단한 awk 접근법이 있습니다.

awk '/string1/ && /string2/' filename

허용 된 답변에 대한 의견을 살펴본 결과 : 아니요, 여러 줄로 수행되지 않습니다. 그러나 그것은 또한 그 질문의 저자가 요구 한 것이 아닙니다.


3

grep을 사용하지 말고 대신 awk를 사용하십시오. grep에서 2 개의 정규 표현식 R1 및 R2를 일치 시키려면 다음과 같이 생각하십시오.

grep 'R1.*R2|R2.*R1'

어색한 동안 :

awk '/R1/ && /R2/'

그러나 R2겹치거나 하위 집합 인 경우 어떻게해야 R1합니까? grep 명령은 awk 명령과 달리 작동하지 않습니다. 당신이 포함하는 행을 찾으려면 말할 수 있습니다 theheat:

$ echo 'theatre' | grep 'the.*heat|heat.*the'
$ echo 'theatre' | awk '/the/ && /heat/'
theatre

이를 위해 2 개의 그렙과 파이프를 사용해야합니다.

$ echo 'theatre' | grep 'the' | grep 'heat'
theatre

물론 실제로 분리되도록 요구 한 경우 grep에서 사용한 것과 동일한 정규 표현식을 항상 awk로 작성할 수 있으며 가능한 모든 시퀀스에서 정규 표현식을 반복하지 않는 대체 awk 솔루션이 있습니다.

이를 제쳐두고, 3 개의 정규 표현식 R1, R2 및 R3에 맞게 솔루션을 확장하려면 어떻게해야합니까? grep에서는 다음과 같은 잘못된 선택 중 하나입니다.

grep 'R1.*R2.*R3|R1.*R3.*R2|R2.*R1.*R3|R2.*R3.*R1|R3.*R1.*R2|R3.*R2.*R1' file
grep R1 file | grep R2 | grep R3

어색하지만 간결하고 명백하며 간단하고 효율적입니다.

awk '/R1/ && /R2/ && /R3/'

이제 정규 표현식 R1 및 R2 대신 리터럴 문자열 S1 및 S2를 실제로 일치 시키려면 어떻게해야합니까? grep을 한 번만 호출하면 단순히 grep을 호출 할 수 없습니다. grep을 호출하기 전에 모든 RE 메타 문자를 이스케이프하는 코드를 작성해야합니다.

S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1')
S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2')
grep 'S1.*S2|S2.*S1'

또는 다시 2 개의 그렙과 파이프를 사용하십시오.

grep -F 'S1' file | grep -F 'S2'

awk에서는 regexp 연산자 대신 문자열 연산자를 사용하면됩니다.

awk 'index($0,S1) && index($0.S2)'

이제 한 줄이 아닌 단락에서 2 개의 정규 표현식을 일치 시키려면 어떻게해야합니까? grep, awk에서 사소한 일을 할 수 없습니다 :

awk -v RS='' '/R1/ && /R2/'

전체 파일에서 어떻습니까? awk에서 grep과 trivial로 다시 수행 할 수 없습니다 (이번에는 간결성을 위해 multi-char RS에 GNU awk를 사용하고 있지만 어떤 awk에서 더 많은 코드가 아니거나 제어 문자를 선택할 수는 없습니다) RS가 동일한 작업을 수행하려면 입력에 있어야합니다.

awk -v RS='^$' '/R1/ && /R2/'

따라서 한 줄이나 단락 또는 파일에서 여러 정규 표현식이나 문자열을 찾으려면 grep을 사용하지 말고 awk를 사용하십시오.


awk '/R1/ && /R2/'대소 문자를 구별는?
Prometheus

@Hashim-아니요. GNU와 그것을 대소 문자를 구분하려면 당신이 할 것 awk가 awk -v IGNORECASE=1 '/R1/ && /R2/'어떤 AWK와awk '{x=toupper($0)} x~/R1/ && x~/R2/'
에드 모튼


2

6 개의 공백으로 시작하고 다음으로 끝나는 행을 찾았습니다.

 cat my_file.txt | grep
 -e '^      .*(\.c$|\.cpp$|\.h$|\.log$|\.out$)' # .c or .cpp or .h or .log or .out
 -e '^      .*[0-9]\{5,9\}$' # numers between 5 and 9 digist
 > nolog.txt

2

파일 테스트 파일에서 여러 단어 수를 찾아야한다고 가정 해 봅시다. 그것에 대해 두 가지 방법이 있습니다

1) 정규식 일치 패턴과 함께 grep 명령을 사용하십시오.

grep -c '\<\(DOG\|CAT\)\>' testfile

2) egrep 명령 사용

egrep -c 'DOG|CAT' testfile 

egrep을 사용하면 표현에 대해 걱정할 필요가 없으며 파이프 구분 기호로 단어를 구분하면됩니다.


2

git grep

git grep여러 패턴과 함께 사용하는 구문은 다음과 같습니다 .

git grep --all-match --no-index -l -e string1 -e string2 -e string3 file

패턴을 , 및 등의 부울 식과 결합 할 수도 있습니다 .--and--or--not

확인 man git-grep도움.


--all-match여러 패턴 표현식을 제공 할 때이 플래그는 모두 일치하는 행이있는 파일로 일치를 제한하도록 지정됩니다 .

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

-l/ --files-with-matches/--name-only 파일 이름 만 표시합니다.

-e다음 매개 변수는 패턴입니다. 기본은 기본 정규 표현식을 사용하는 것입니다.

고려해야 할 다른 매개 변수 :

--threads 사용할 grep worker 스레드 수

-q/ --quiet/ --silent출력하지 않습니다 일치하는 라인; 일치하는 경우 상태 0으로 종료하십시오.

패턴 유형을 변경하려면 -G/ --basic-regexp(기본값), -F/ --fixed-strings, -E/ --extended-regexp, -P/를 사용할 수도 있습니다 --perl-regexp.-f file 및 기타.

관련 :

들어 OR의 작동을 참조하십시오


2
항상 "git grep"은 git 저장소 내에서만 실행할 수 있다고 생각했습니다. --no-index 옵션을 알지 못했습니다. 지적 해 주셔서 감사합니다!
Kamaraju Kusumanchi 19

1

grep하려는 문자열을 파일에 넣습니다.

echo who    > find.txt
echo Roger >> find.txt
echo [44][0-9]{9,} >> find.txt

그런 다음 -f를 사용하여 검색

grep -f find.txt BIG_FILE_TO_SEARCH.txt 

1
grep '(string1.*string2 | string2.*string1)' filename

어떤 순서로든 string1 및 string2와 함께 줄을 가져옵니다.


적어도 두 가지 답변과 다른 점은 무엇입니까?
luk2302

1
grep -i -w 'string1\|string2' filename

이것은 -i가 사용되므로 정확한 단어 일치 및 대소 문자를 구분하지 않는 단어에 적용됩니다.


0

여러 줄로 일치하는 경우 :

echo -e "test1\ntest2\ntest3" |tr -d '\n' |grep "test1.*test3"

또는

echo -e "test1\ntest5\ntest3" >tst.txt
cat tst.txt |tr -d '\n' |grep "test1.*test3\|test3.*test1"

개행 문자 만 제거하면 작동합니다!


0

당신은 grep이것을 좋아 해야 합니다 :

$ grep 'string1' file | grep 'string2'

1
이것은 논리 AND를 수행합니다. OP는 논리 OR을 원합니다.
벤 휠러

1
@ BenWheeler : 질문에서 : "그래서 두 문자열을 포함하는 줄만 grep과 어떻게 일치합니까?"
Erik I

0

나는 종종 당신과 같은 문제에 부딪치며 방금 스크립트를 썼습니다.

function m() { # m means 'multi pattern grep'

    function _usage() {
    echo "usage: COMMAND [-inH] -p<pattern1> -p<pattern2> <filename>"
    echo "-i : ignore case"
    echo "-n : show line number"
    echo "-H : show filename"
    echo "-h : show header"
    echo "-p : specify pattern"
    }

    declare -a patterns
    # it is important to declare OPTIND as local
    local ignorecase_flag  filename linum header_flag colon result OPTIND

    while getopts "iHhnp:" opt; do
    case $opt in
        i)
        ignorecase_flag=true ;;
        H)
        filename="FILENAME," ;;
        n)
        linum="NR," ;;
        p)
        patterns+=( "$OPTARG" ) ;;
        h)
        header_flag=true ;;
        \?)
        _usage
        return ;;
    esac
    done

    if [[ -n $filename || -n $linum ]]; then
    colon="\":\","
    fi

    shift $(( $OPTIND - 1 ))

    if [[ $ignorecase_flag == true ]]; then
    for s in "${patterns[@]}"; do
            result+=" && s~/${s,,}/"
    done
    result=${result# && }
    result="{s=tolower(\$0)} $result"
    else
    for s in "${patterns[@]}"; do
            result="$result && /$s/"
    done
    result=${result# && }
    fi

    result+=" { print "$filename$linum$colon"\$0 }"

    if [[ ! -t 0 ]]; then       # pipe case
    cat - | awk "${result}"
    else
    for f in "$@"; do
        [[ $header_flag == true ]] && echo "########## $f ##########"
        awk "${result}" $f
    done
    fi
}

용법:

echo "a b c" | m -p A 
echo "a b c" | m -i -p A # a b c

원한다면 .bashrc에 넣을 수 있습니다.


0

두 문자열이 순서대로 정렬되면 on grep명령 사이에 패턴을 넣습니다 .

$ grep -E "string1(?.*)string2" file

다음 행이 파일에 포함 된 경우의 예 Dockerfile:

FROM python:3.8 as build-python
FROM python:3.8-slim

: 문자열이 포함 된 행 얻으려면 FROM pythonas build-python다음을 사용 :

$ grep -E "FROM python:(?.*) as build-python" Dockerfile

그런 다음 출력에는 두 문자열모두 포함 된 행만 표시됩니다 .

FROM python:3.8 as build-python

-2

ripgrep

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

rg -N '(?P<p1>.*string1.*)(?P<p2>.*string2.*)' file.txt

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

특히 큰 데이터로 작업 할 때 사용하십시오.

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


1
이 답변은 옳지 않습니다. 명명 된 캡처 그룹은 불필요하며 string2이전에 표시 될 경우를 처리하지 않습니다 string1. 이 문제에 대한 가장 간단한 해결책은 rg string1 file.txt | rg string2입니다.
BurntSushi5'1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.