n 자릿수 그룹을 grep하는 방법, n 이하의 숫자는?


33

저는 Linux를 배우고 있는데, 스스로 해결하지 못하는 것 같습니다. 여기있어:

한 행에 4 개의 숫자를 포함하지만 4를 초과하지 않는 파일에서 행을 grep하십시오.

어떻게 접근 해야할지 모르겠습니다. 문자열에서 특정 숫자는 검색 할 수 있지만 그 숫자는 검색 할 수 없습니다.


2
같은 줄을 1234a12345표시 해야합니까 ?
Eliah Kagan

@Buddha 당신은 예와 함께 질문을 설명해야합니다.
Avinash Raj

숫자 앞에 공백 또는 줄 앵커의 시작이 있고 그 뒤에 공백 또는 줄 앵커의 끝이 오는 경우 단어 경계를 사용하면됩니다. \b\d{4}\b
Avinash Raj

1
이 질문은 grep 사용법 에 대해 명시 적이라는 점에서 정규 표현식에 대한 일부 질문과 다릅니다 . grep, sed 및 awk와 같은 Ubuntu에서 Unix 유틸리티 사용에 대한 질문은 여기에서 항상 좋은 것으로 간주되었습니다. 때때로 사람들은 잘못된 도구 로 일하는 법을 묻습니다 . 문맥의 부족은 큰 문제이지만 여기서 일어나고있는 것은 아닙니다. 이는 주제에 관한 것으로, 유용한 답변을 제공 할 수있을만큼 명확하며 커뮤니티에 도움이되며 추가 답변을 방지하거나 삭제 또는 이전을 향한 추진에는 도움이되지 않습니다. 다시 열기로 투표하고 있습니다.
Eliah Kagan

1
정말 감사합니다.이 피드백을 많이받을 줄은 몰랐습니다. 이것은 내가 찾고있는 대답입니다 : grep -E '(^ ​​| [^ 0-9]) [0-9] {4} ($ | [^ 0-9])'파일. 명령은 다음과 같은 문자열을 가져올 수 있어야합니다. abc1234abcd99999
Buddha

답변:


52

이 질문을 해석하는 두 가지 방법이 있습니다. 두 경우 모두 해결하겠습니다. 라인을 표시 할 수 있습니다.

  1. 더 이상 일련의 자릿수에 속하지 않는 네 자릿수의 시퀀스를 포함 하거나
  2. 4 자리 시퀀스를 포함하지만 더 이상 숫자 시퀀스를 포함하지 않습니다 (별도).

예를 들어 (1)은을 표시 1234a56789하지만 (2)는 표시하지 않습니다.


더 이상 일련의 숫자가 아닌 일련의 4 자리 숫자를 포함하는 모든 행을 표시하려면 한 가지 방법이 있습니다.

grep -P '(?<!\d)\d{4}(?!\d)' file

이것은 Perl 정규 표현식을 사용하는데 , 우분투 grep( GNU grep )는 via를 지원합니다 -P. 와 같은 텍스트와 일치하지 않거나 그 일부 또는 12345일치하지 않습니다 . 하지만 그것은 일치 의를 .1234234512341234a56789

Perl 정규식에서 :

  • \d는 모든 숫자를 의미합니다 ( [0-9]또는 말하기 쉬운 방법입니다 [[:digit:]]).
  • x{4}x4 번 일치합니다 . ( { }구문은 Perl 정규 표현식에만 국한된 것이 아니라 확장 정규 표현식 grep -E에도 적용됩니다.) \d{4}와 동일합니다 \d\d\d\d.
  • (?<!\d)너비가 0 인 음수 룩 어설 션입니다. "이 앞에 오지 않는 한"을 의미합니다 \d.
  • (?!\d)너비가 0 인 네거티브 미리보기 어설 션입니다. "이 뒤에 오지 않으면"을 의미합니다 \d.

(?<!\d)그리고 (?!\d)네 자리 숫자의 순서 외부 텍스트와 일치하지 않는다; 대신, (함께 사용될 때) 긴 자릿수의 일부인 경우 네 자릿수의 시퀀스 자체가 일치하지 않도록합니다.

가장 오른쪽 또는 가장 왼쪽에있는 4 자리 하위 시퀀스가 ​​여전히 일치하므로 Look-Behind 또는 Look-Ahead를 사용하는 것만으로는 충분하지 않습니다.

look-behind 및 look-ahead 어설 션 을 사용하면 패턴이 주변 텍스트가 아닌 4 자리 시퀀스 만 일치한다는 이점 이 있습니다. 이 --color옵션 은 색상 강조 표시를 사용할 때 유용합니다 ( 옵션 포함).

ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4

기본적으로 우분투, 각 사용자가 alias grep='grep --color=auto'자신의 ~.bashrc파일 . 따라서 grep( 별칭 이 확장되는 경우)로 시작하는 간단한 명령을 실행 하고 표준 출력터미널 (이것이 확인하는 것) 인 경우 색상 강조 표시가 자동으로 나타납니다 . 일치 항목은 일반적으로 빨간색 음영 ( vermilion에 가까운 ) 으로 강조 표시 되지만 기울임 꼴 굵은 체로 표시되었습니다. 스크린 샷은 다음과 같습니다.--color=auto
12345abc789d0123e4를 출력으로 사용하고 0123을 빨간색으로 강조 표시 한 grep 명령을 보여주는 스크린 샷

또한 다음 grep과 같이 전체 줄이 아닌 일치하는 텍스트 만 인쇄 할 수 있습니다 -o.

ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123

뒤돌아보기 및 미리보기 어설 션이 없는 대체 방법

그러나 다음과 같은 경우 :

  1. 또한 시스템에서 실행 명령 필요가 grep지원하지 않는 -P펄 정규 표현식을 사용하지 않으려는 달리 또는,
  2. 이렇게 특별히 네 자리 숫자 일치 할 필요는 없습니다 - 일반적으로 어떤 경우인지 당신의 목표는 일치하는 항목을 포함하는 디스플레이 라인에 간단 경우, 그리고
  3. 조금 덜 우아한 솔루션으로 괜찮습니다.

... 그러면 확장 정규 표현식을 사용 하여이를 달성 할 수 있습니다 .

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

네 자리 숫자와 숫자가 아닌 문자 (또는 줄의 시작 또는 끝)와 일치합니다. 구체적으로 :

  • [0-9]모든 숫자 (예 [[:digit:]]: 또는 \dPerl 정규식)와 일치 {4}하며 "네 번"을 의미합니다. 따라서 [0-9]{4}네 자리 시퀀스와 일치합니다.
  • [^0-9]하지 않는 범위에서 문자와 일치 0를 통해 9. 그것은과 동일 [^[:digit:]](또는 \D펄 정규 표현식으로).
  • ^[ ]괄호 안에 표시되지 않으면 줄의 시작과 일치합니다. 마찬가지로 $줄의 끝과 일치합니다.
  • |평균 또는 괄호는 대수에서와 같이 그룹화하기위한 것입니다. 따라서 (^|[^0-9])줄의 시작 또는 숫자가 아닌 문자 ($|[^0-9])와 일치하는 반면 줄의 끝 또는 숫자가 아닌 문자 와 일치합니다.

따라서 일치 [0-9]{4}는 동시에 네 자리 시퀀스 ( )를 포함하는 행에서만 발생합니다 .

  • 줄의 시작 부분 또는 앞에 숫자가 아닌 문자 ( (^|[^0-9]))가 있고
  • 줄 끝에서 또는 숫자가 아닌 숫자 ( ($|[^0-9]))가 옵니다 .

반면에, 당신은 네 자리 시퀀스를 포함하는 모든 행을 표시하는 것이 아니라 포함되지 않은하려면 어떤 개념적으로 다음, 이상 네 자리 (네 개의 숫자의 또 다른 시퀀스와 분리 된 경우에도 하나)의 순서를 당신의 목표는 한 패턴과 일치하지만 다른 패턴과 일치하지 않는 선을 찾는 것입니다.

따라서 단일 패턴으로 수행하는 방법을 알고 있더라도 matt의 두 번째 제안 과 같은 것을 사용 grep하여 두 패턴을 따로 제안 하는 것이 좋습니다 .

이를 수행 할 때 Perl 정규식의 고급 기능을 강하게 활용하지 않기 때문에 사용하지 않는 것이 좋습니다. 그러나 위의 스타일을 유지하기 위해 다음 대신에 (및 중괄호)를 사용 하는 matt의 솔루션 이 단축 \d되었습니다 [0-9].

grep -P '\d{4}' file | grep -Pv '\d{5}'

그것은 사용하기 때문에 [0-9], 매트의 방법은 더 휴대용 - 그것은 시스템에서 작동 grep펄 정규 표현식을 지원하지 않습니다. 당신이 사용하는 경우 [0-9](또는 [[:digit:]]) 대신 \d하지만, 계속 사용 { }하면 매트의 방식의 휴대 성을 좀 더 간결하게 얻을 :

grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'

단일 패턴으로 대체 방법

당신이 정말로 grep명령을 선호한다면

  1. 단일 정규 표현식을 사용합니다 ( 위와 같이 파이프로grep 구분 된 두 개가 아님 )
  2. 적어도 하나의 4 자리 숫자 시퀀스를 포함하는 행을 표시합니다.
  3. 5 자리 이상의 시퀀스는 없습니다.
  4. 그리고 당신은 숫자뿐만 아니라 전체 줄을 일치시키는 것을 신경 쓰지 않습니다 (아마도 이것을 신경 쓰지 않을 것입니다)

... 다음을 사용할 수 있습니다.

grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file

-x플래그 차종은 grep오직 선을 표시 곳 전체 라인 일치 (보다는 어떤 라인을 포함 일치).

나는 Perl 정규식을 사용했다. 왜냐하면 나는 이 경우 의 간결함이 간결 \d하고 \D명확성을 높이기 때문이다. 당신이 시스템에 휴대용 뭔가가 필요하지만 grep지원하지 않습니다 -P, 당신은 그들을 대체 할 수 [0-9][^0-9](또는과 [[:digit:]][^[:digit]]) :

grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file

이 정규 표현식의 작동 방식은 다음과 같습니다.

  • 가운데 \d{4}또는 [0-9]{4}네 자리의 한 시퀀스와 일치합니다. 우리는 이것들 중 하나 이상을 가질 수 있지만, 적어도 하나는 있어야합니다.

  • 왼쪽에서 (\d{0,4}\D)*또는 4 자리 이하의 ([0-9]{0,4}[^0-9])*0 개 이상의 *인스턴스 ( ) 와 일치하고 숫자가 아닌 숫자 와 일치합니다 . 0 자리 숫자 (즉, 아무것도 아님)는 "4 자리 이하의 숫자"일 가능성이 있습니다. 이 경기 의 (a) 빈 문자열 또는 (b)에 임의의 문자열 이 아닌 자리에서 이상 네 자리 숫자의 시퀀스를 포함하지 않는.

    중앙 \d{4}(또는 [0-9]{4}) 의 바로 왼쪽에있는 텍스트 는 비어 있거나 숫자가 아닌 숫자로 끝나야하므로 중앙 \d{4}에서 왼쪽에 다른 다섯 번째 숫자가있는 네 자리 숫자와 일치 하지 않습니다.

  • 오른쪽에서 (\D\d{0,4})*또는 숫자가 아닌 ([^0-9][0-9]{0,4})*0 개 이상의 *인스턴스와 그 뒤에 4 자리를 넘지 않습니다 (이전과 같이 4, 3, 2, 1 또는 전혀 없음). 이 경기 의 (a) 빈 문자열 또는 (b)에 임의의 문자열 시작 이 아닌 자리에서 이상 네 자리 숫자의 시퀀스를 포함하지 않는.

    중앙 \d{4}(또는 [0-9]{4}) 의 바로 오른쪽에있는 텍스트 는 비어 있거나 숫자가 아닌 숫자로 시작해야하므로 중앙 \d{4}에서 오른쪽에 다른 다섯 번째 숫자가있는 네 자리 숫자가 일치 하지 않습니다.

이를 통해 어딘가에 4 자리 시퀀스가 ​​존재하고, 5 개 이상의 숫자 시퀀스가 ​​어디에도 존재하지 않게됩니다.

이런 식으로하는 것은 나쁘거나 잘못이 아닙니다. 그러나이 대안을 고려해야 할 가장 중요한 이유 는 위에 제안 된 것과 매트의 대답 에서 대신 (또는 유사한) 사용의 이점을 분명히하기 때문 입니다.grep -P '\d{4}' file | grep -Pv '\d{5}'

그렇게하면 목표는 하나만 포함하고 다른 것은 포함하지 않는 줄을 선택하는 것이 분명합니다. 또한 구문이 더 간단합니다 (많은 독자 / 관리자가 더 빨리 이해할 수 있음).


9

이렇게하면 4 개의 숫자가 연속으로 표시되지만 더 이상은 표시되지 않습니다

grep '[0-9][0-9][0-9][0-9][^0-9]' file

^는

문제를 해결하는 방법을 모르겠지만 문제가 있습니다 ... 번호가 줄의 끝이면 표시되지 않습니다.

그러나이 추한 버전은 그 경우에 효과가 있습니다.

grep '[0-9][0-9][0-9][0-9]' file | grep -v [0-9][0-9][0-9][0-9][0-9]

죄송합니다, egrep 필요가 없습니다-편집했습니다
matt

2
첫 번째는 틀리다 . a12345b왜냐하면 그것이 일치하기 때문이다 2345b.
Volker Siegel 1

0

경우 grep펄 정규식을 (지원하지 않습니다 -P), 다음 쉘 명령을 사용합니다 :

grep -w "$(printf '[0-9]%.0s' {1..4})" file

어디에서 printf '[0-9]%.0s' {1..4}4 배를 생산할 것인가 [0-9]. 이 방법은 긴 자릿수가 있고 패턴을 반복하지 않으려는 경우에 유용합니다 ( 4찾을 자릿수로 바꾸 십시오).

를 사용 -w하면 전체 단어를 찾습니다. 그러나와 같은 영숫자 문자열에 관심이 있다면 패턴의 끝에 1234a추가하십시오 [^0-9].

grep "$(printf '[0-9]%.0s' {1..4})[^0-9]" file

사용 $()은 기본적으로 명령 대체 입니다. 패턴을 반복하는 방법을 보려면 이 게시물 을 확인하십시오 printf.


0

file시스템에서 실제 파일 이름 으로 바꾸어 아래 명령을 시도 할 수 있습니다 .

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

grep 명령의 추가 사용법에 대해서는 이 학습서 를 확인할 수도 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.