패턴 후 내용을 grep하는 방법은 무엇입니까?


81

예를 들어 다음과 같은 파일이 있습니다.

potato: 1234
apple: 5678
potato: 5432
grape: 4567
banana: 5432
sushi: 56789

로 시작하는 모든 줄에 대해 grep하고 potato:있지만 뒤에 오는 숫자 만 파이프 하고 싶습니다 potato:. 따라서 위의 예에서 출력은 다음과 같습니다.

1234
5432

어떻게 할 수 있습니까?

답변:


113
grep 'potato:' file.txt | sed 's/^.*: //'

grep문자열이 포함 된 모든 줄을 potato:찾은 다음 각 줄에 대해 줄의 시작 부분 ( )에서 시퀀스의 마지막 발생 (콜론 뒤에 공백이 있음 )까지 모든 문자 ( )를 빈 문자로 sed바꿉니다 ( s///-대체). 문자열 ( -첫 번째 부분을 비어있는 두 번째 부분으로 대체)..*^:s/...//

또는

grep 'potato:' file.txt | cut -d\   -f2

포함 된 각 라인의 경우 potato:, cut공백으로 구분 된 여러 필드에 선 분할합니다 ( -d\- d= 구분 기호를, \= 공백 문자, 같은 탈출 -d" "(도 일한 것) 각각 같은 라인의 두 번째 필드를 인쇄 -f2).

또는

grep 'potato:' file.txt | awk '{print $2}'

포함 된 각 라인에 대해 potato:, awk두 번째 필드 (인쇄 될 print $2공간에 의해 디폴트로 구분된다).

또는

grep 'potato:' file.txt | perl -e 'for(<>){s/^.*: //;print}'

포함 된 모든 행은에서 모든 행을 가져 오는 potato:인라인 ( -e) Perl 스크립트 로 전송 된 stdin다음 이러한 각 행에 대해 위의 첫 번째 예에서와 동일한 대체를 수행 한 다음 인쇄합니다.

또는

awk '{if(/potato:/) print $2}' < file.txt

이 파일을 통해 전송된다 stdin( < file.txt를 통해 파일의 내용을 전송 stdin에 왼쪽에있는 명령에) awk포함하는 각 라인, 해당 스크립트 potato:( if(/potato:/)정규 표현식이 경우 true를 반환 /potato:/설명 된 바와 같이, 두 번째 필드를 현재 행을 일치), 인쇄 위.

또는

perl -e 'for(<>){/potato:/ && s/^.*: // && print}' < file.txt

파일은 stdin( < file.txt, 위 참조)를 통해 위의 것과 유사하게 작동하는 Perl 스크립트 로 전송 되지만 이번에는 각 행에 문자열이 포함되어 있는지 확인합니다 potato:( /potato:/현재 행 에이 포함 된 경우 일치하는 정규식 potato:이고 ( &&)를 수행 한 다음 위에서 설명한 정규식을 적용하고 결과를 인쇄합니다.


3
두 개의 프로세스와 파이프가 필요하지 않습니다. 나는 갈 것이다 awk '$1 ~ /potato/ { print $2 }' file.txt.
musiphil 2013

2
AWK 하나 더 관용구 것awk '/potato:/ {print $2}'
벤자민 W.

펄 스크립트에서 이익을 얻을 수perl -pe
tripleee

60

또는 정규식 어설 션을 사용하십시오. grep -oP '(?<=potato: ).*' file.txt


4
위에서 받아 들여진 답변 중 한 줄을 시도했지만이 답변이 질문을 더 정확하게 해결한다고 생각합니다.
Jake88

3
일부 설명 : 옵션 -o은 행의 일치하는 부분 만 인쇄하는 것을 의미합니다. 반면 -P에 Perl 호환 정규식을 유추하는 반면 regex를 긍정적으로 살펴(?<=string) 봅니다.
Serge Stroobandt 2016 년

9
sed -n 's/^potato:[[:space:]]*//p' file.txt

Grep을 제한된 Sed로 생각하거나 Sed를 일반화 된 Grep로 생각할 수 있습니다. 이 경우 Sed는 원하는 작업을 수행하는 훌륭하고 가벼운 도구 중 하나입니다. 물론이를 수행 할 수있는 다른 여러 가지 합리적인 방법도 있습니다.


2

이것은 같은 줄에만 각 일치 후 모든 것을 인쇄합니다.

perl -lne 'print $1 if /^potato:\s*(.*)/' file.txt

이것은 모든 후속 행도 인쇄한다는 점을 제외하면 동일합니다.

perl -lne 'if ($found){print} elsif (/^potato:\s*(.*)/){print $1; $found++}' file.txt

다음 명령 줄 옵션이 사용됩니다.

  • -n 입력 파일의 각 줄을 반복
  • -l 처리하기 전에 줄 바꿈을 제거하고 나중에 다시 추가합니다.
  • -e Perl 코드 실행

2
grep -Po 'potato:\s\K.*' file

-P Perl 정규식을 사용하려면

-o 일치 만 출력

\s 이후의 공간에 맞게 potato:

\K 경기를 생략하다

.* 나머지 문자열과 일치


1

다른 답변 상태로 grep을 사용할 수 있습니다. 그러나 grep, awk, sed, perl, cut 또는 외부 도구는 필요하지 않습니다. 순수한 bash로 할 수 있습니다.

이것을 시도하십시오 (세미콜론은 당신이 그것을 모두 한 줄에 넣을 수 있도록 거기에 있습니다) :

$ while read line;
  do
    if [[ "${line%%:\ *}" == "potato" ]];
    then
      echo ${line##*:\ };
    fi;
  done< file.txt

## bash는 $ line에서 가장 긴 ":"일치를 맨 앞에서 삭제하도록 지시합니다.

$ while read line; do echo ${line##*:\ }; done< file.txt
1234
5678
5432
4567
5432
56789

또는 값 대신 키를 원하면 %%는 bash에게 $ line에서 가장 긴 일치 항목 인 ":"을 끝에서 삭제하도록 지시합니다.

$ while read line; do echo ${line%%:\ *}; done< file.txt
potato
apple
potato
grape
banana
sushi

분할 할 부분 문자열은 ": \"입니다. 공백 문자는 백 슬래시로 이스케이프되어야하기 때문입니다.

Linux 문서 프로젝트 에서 이와 유사한 것을 더 많이 찾을 수 있습니다 .


while read매우 느립니다. 외부 유틸리티를 사용하는 것은 실제로 버퍼링 된 I / O가있는 것을 선택하는 한 훨씬 더 빠를 것입니다 (즉,이 답변에서 언급 한 것 중 하나와 다른 많은 것).
tripleee

또한 read -rPOSIX 이전의 다소 성가신 레거시 동작을 특별히 요구하지 않는 한 사용해야합니다 .
tripleee

0

최신 BASH는 정규 표현식을 지원합니다.

while read -r line; do
  if [[ $line =~ ^potato:\ ([0-9]+) ]]; then
    echo "${BASH_REMATCH[1]}"
  fi
done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.