it-gundan.com

파이프 문자가있는 패턴으로 여러 패턴을 grep하려면 어떻게합니까?

두 파일 중 하나와 일치하는 여러 파일에서 모든 줄을 찾고 싶습니다. 입력하여 찾고있는 패턴을 찾으려고 노력했습니다.

grep (foo|bar) *.txt

그러나 쉘은 |를 파이프로 사용하고 bar이 (가) 실행 파일이 아닌 경우 불평합니다.

동일한 파일 세트에서 여러 패턴을 grep하려면 어떻게해야합니까?

681
Dan

먼저, 셸이 패턴을 확장하지 못하도록 보호해야합니다. 가장 쉬운 방법은 작은 따옴표를 묶는 것입니다. 작은 따옴표는 백 슬래시를 포함하여 그 사이에 어떤 것도 확장하지 못하게합니다. 당신이 할 수없는 유일한 패턴에 작은 따옴표가 있습니다.

grep -- 'foo*' *.txt

(또한 -- end-of-option-marker는 GNU grep라는 파일을 처리하는 것을 포함하여 일부 grep 구현을 중지합니다. -foo-.txt 예를 들어 (*.txt에서 Shell에 의해 확장되어 옵션이 아닌 인수를 따르더라도) 옵션으로 사용됩니다.

작은 따옴표가 필요한 경우 '\'' (끝 문자열 리터럴, 리터럴 따옴표, 열린 문자열 리터럴)로 쓸 수 있습니다.

grep -- 'foo*'\''bar' *.txt

둘째, grep은 패턴에 대해 적어도 두 가지 구문을 지원합니다. 오래된 기본 구문 ( basic regular expressions )은 대체 (|) 연산자를 지원하지 않지만 일부 버전에서는 확장명을 사용하지만 백 슬래시로 작성됩니다.

grep -- 'foo\|bar' *.txt

이식 가능한 방법은 최신 구문 인 확장 정규 표현식 을 사용하는 것입니다. -E 옵션을 grep에 전달하여 선택해야합니다 (이전에는 egrep 개별 명령 ²으로 수행됨).

grep -E -- 'foo|bar' *.txt

분리를 사용하여 복잡한 패턴을 만드는 것과 달리 여러 패턴 중 하나를 찾고있을 때의 또 다른 가능성은 여러 패턴을 grep에 전달하는 것입니다. 각 패턴 앞에 -e 옵션을 붙여서이를 수행 할 수 있습니다.

grep -e foo -e bar -- *.txt

또는 여러 줄에 패턴을 넣습니다.

grep -- 'foo
bar' *.txt

또는 해당 패턴을 한 줄에 하나씩 파일에 저장하고 실행하십시오.

grep -f that-file -- *.txt

*.txt이 단일 파일로 확장되면 grep는 파일이 둘 이상있을 때와 같이 이름이 일치하는 행을 접두사로 사용하지 않습니다. 이를 해결하기 위해 GNU grep와 같은 grep 구현으로 -H 옵션을 사용하거나 모든 구현에서 /dev/null을 추가 인수로 전달할 수 있습니다.


¹ 일부 grep 구현은 -P 또는 augmented-X, -K...

² 반면 egrep는 POSIX에서 더 이상 사용되지 않으며 POSIX 또는 GNU 유틸리티가 설치되지 않은 경우 일부 시스템, Solaris와 같은 다른 시스템에서 더 이상 발견되지 않는 경우가 있음) /bin/grep-e, -f, -E, \| 또는 여러 줄 패턴

egrep "foo|bar" *.txt

또는

grep "foo\|bar" *.txt
grep -E "foo|bar" *.txt

gnu-grep 매뉴얼 페이지를 선택적으로 인용 :

   -E, --extended-regexp
          Interpret PATTERN as an extended regular expression (ERE, see below).  (-E is specified by POSIX.)

Matching Control
   -e PATTERN, --regexp=PATTERN
          Use PATTERN as the pattern.  This can be used to specify multiple search patterns, or to protect  a  pattern
          beginning with a hyphen (-).  (-e is specified by POSIX.)

(...)

   grep understands two different versions of regular expression syntax: “basic” and “extended.”  In  GNU grep,  there
   is  no  difference  in  available  functionality  using  either  syntax.   In  other implementations, basic regular
   expressions are less powerful.  The following description applies to extended regular expressions; differences  for
   basic regular expressions are summarized afterwards.

처음에는 더 이상 읽지 않았으므로 미묘한 차이점을 인식하지 못했습니다.

Basic vs Extended Regular Expressions
   In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead  use  the
   backslashed versions \?, \+, \{, \|, \(, and \).

나는 예제에서 배웠기 때문에 항상 egrep을 사용했고 불필요하게 parens을 사용했습니다. 이제 새로운 것을 배웠습니다. :)

109
user unknown

TC1이 말했듯이 -F 사용 가능한 옵션 인 것 같습니다 :

$> cat text
some text
foo
another text
bar
end of file

$> patterns="foo
bar" 

$> grep -F "${patterns}" text
foo
bar

먼저 특수 문자에 따옴표를 사용해야합니다. 둘째, 그럼에도 불구하고 grep는 교대를 직접 이해하지 못합니다. egrep 또는 (GNU grep 만 해당) grep -E.

egrep 'foo|bar' *.txt

(대체가 더 큰 정규식의 일부가 아니면 괄호는 필요하지 않습니다.)

17
geekosaur

정규 표현식이 필요하지 않은 경우 fgrep 또는 grep -F를 여러 개의 -e 매개 변수와 함께 사용하는 것이 훨씬 빠릅니다.

fgrep -efoo -ebar *.txt

fgrep (또는 grep -F)는 정규 표현식 대신 고정 문자열을 검색하기 때문에 일반 grep보다 훨씬 빠릅니다.

8
Moustafa Elqabbany

아래 명령을 사용하여 결과를 얻을 수 있습니다.

egrep 'rose.*Lotus|lotus.*rose' some_file
6
Abhishek

파이프 (|)는 특수한 셸 문자이므로 이스케이프 처리 (\|)하거나 설명서 ( man bash )에 따라 인용해야합니다. :

견적은 특별한 의미를 제거하기 위해 사용됩니다 쉘에 대한 특정 문자 나 단어. 특수 문자에 대한 특수 처리를 비활성화하고 예약어가 인식되지 않도록하고 매개 변수 확장을 방지하는 데 사용할 수 있습니다.

큰 따옴표로 문자를 묶으면 리터럴 값이 유지됩니다 따옴표 안의 모든 문자

따옴표가없는 백 슬래시 (\)는 이스케이프 문자입니다.

참조 : Bash에서 어떤 문자를 이스케이프해야합니까?

다음은 몇 가지 예입니다 (아직 언급되지 않은 도구 사용).

  • ripgrep 사용 :

    • rg "foo|bar" *.txt
    • rg -e foo -e bar *.txt
  • git grep 사용 :

    • git grep --no-index -e foo --or -e bar

      참고 : --and, --or--not와 같은 부울 식도 지원합니다.

라인 당 AND 연산에 대해서는 다음을 참조하십시오 : 여러 AND 패턴으로 grep을 실행하는 방법?

파일 당 AND 연산은 다음을 참조하십시오. 파일에 여러 문자열 또는 정규식이 모두 있는지 확인하는 방법?

4
kenorb

여러 패턴을 잡기위한 싸고 쾌활한 방법 :

$ echo "foo" > ewq ; echo "bar" >> ewq ; grep -H -f ewq *.txt ; rm ewq
3
DHDHDHD

날짜가 어리석게 형식화 된 액세스 로그가 있습니다 : [30/Jun/2013 : 08 : 00 : 45 +0200]

그러나 나는 그것을 다음과 같이 표시해야했습니다 : 30/Jun/2013 08:00:45

문제는 grep 문에서 "OR"을 사용하면 두 개의 별도 줄에 두 개의 일치 표현식이 수신된다는 것입니다.

해결책은 다음과 같습니다.

grep -in myURL_of_interest  *access.log  | \
grep -Eo '(\b[[:digit:]]{2}/[[:upper:]][[:lower:]]{2}/[[:digit:]]{4}|[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\b)'   \
| paste - - -d" " > MyAccess.log
3
tsmets

TL; DR : 여러 패턴 중 하나를 일치시킨 후 더 많은 일을하려면 \(pattern1\|pattern2\)

예 : 이름 'date'를 포함하는 변수가 String 또는 int로 정의 된 모든 장소를 찾고 싶습니다. (예 : "int cronDate ="또는 "String textFormattedDateStamp =") :

cat myfile | grep '\(int\|String\) [a-zA-Z_]*date[a-zA-Z_]* =' 

grep -E를 사용하면 괄호 나 파이프를 벗어날 필요가 없습니다 (예 : grep -E '(int|String) [a-zA-Z_]*date[a-zA-Z_]* ='

2
jeremysprofile

이것은 나를 위해 작동

[email protected]:/home/sshuser# aws ec2 describe-instances --instance-ids i-2db0459d |grep 'STATE\|TAG'

**STATE**   80      stopped

**STATE**REASON     Client.UserInitiatedShutdown    Client.UserInitiatedShutdown: User initiated shutdown

**TAGS**    Name    Magento-Testing [email protected]:/home/sshuser#
1
Mansur Ali

여러 가지 방법이 있습니다.

  1. grep 'foo\|bar' *.txt
  2. egrep 'foo|bar' *.txt
  3. find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'
  4. find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'

세 번째 및 네 번째 옵션은 파일에서만 grep하고 .txt 이름으로.
따라서 사용 사례에 따라 위에서 언급 한 옵션 중 하나를 사용할 수 있습니다.
감사!!

1
Bhagyesh Dudhediya

탭과 공백이 포함 된 여러 패턴이있는 경우 @ geekosaur 's answer 에 추가하려면 다음 명령을 사용하십시오.

grep -E "foo[[:blank:]]|bar[[:blank:]]"

어디 [[:blank:]]는 공백 또는 탭 문자를 나타내는 RE 문자 클래스입니다.

1
Fuseteam