주변 문자를 인쇄하지 않고 'sed'와 일치하는 정규식 추출


24

모든 'sed'의사들에게 :

줄에서 일치하는 정규식을 추출하기 위해 'sed'를 얻는 방법은 무엇입니까?

즉, 포함 줄의 모든 일치하지 않는 문자가 제거 된 정규식에 해당하는 문자열 만 원합니다.

아래와 같은 역 참조 기능을 사용해 보았습니다.

regular expression to be isolated 
         gets `inserted` 
              here     
               |
               v  
 sed -n 's/.*\( \).*/\1/p 

이것은 다음과 같은 일부 표현식에서 작동합니다.

 sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p 

'CONFIG_ ....'(일부 '* .h'파일에 있음)로 시작하는 모든 매크로 이름을 깔끔하게 추출하고 한 줄씩 모두 인쇄합니다.

          CONFIG_AT91_GPIO
          CONFIG_DRIVER_AT91EMAC
                   .
                   .   
          CONFIG_USB_ATMEL
          CONFIG_USB_OHCI_NEW
                   .
                 e.t.c. 

그러나 위의 내용은 다음과 같이 분류됩니다.

  sed -n 's/.*\([0-9][0-9]*\).*/\1/p 

이것은 항상 다음과 같은 한 자리를 반환합니다

                 7
                 9
                 .
                 .  
                 6

연속 번호 필드를 추출하는 대신.

              8908078
              89670890  
                 .
                 .  
                 .
               23019   
                 .
               e.t.c.  

추신 : 'sed'에서 이것이 어떻게 달성되는지에 대한 피드백에 감사드립니다. 'grep'과 'awk'로이 작업을 수행하는 방법을 알고 있습니다 .'sed '에 대한 이해가 제한되어 있지만'sed '에 구멍이 있는지, 내가
가지고 있는'sed '에이 작업을 수행 할 수있는 방법이 있는지 알고 싶습니다 . 단순히 간과했다.

답변:


22

정규 표현식에 그룹이 포함되어 있으면 문자열을 일치시키는 여러 가지 방법이있을 수 있습니다. 그룹이있는 정규 표현식이 모호합니다. 예를 들어, regexp ^.*\([0-9][0-9]*\)$및 string을 고려하십시오 a12. 두 가지 가능성이 있습니다.

  • 일치 a.*2에 대해 [0-9]*; 1와 일치합니다 [0-9].
  • a1에 대해 일치 .*하고 빈 문자열에 대해 [0-9]*; 2와 일치합니다 [0-9].

Sed는 다른 모든 정규 표현식 도구와 마찬가지로 가장 긴 일치 규칙을 적용합니다. 먼저 첫 번째 가변 길이 부분을 가능한 한 긴 문자열과 일치시킵니다. 나머지 문자열을 나머지 정규 표현식과 일치시키는 방법을 찾으면 좋습니다. 그렇지 않으면 sed는 첫 번째 가변 길이 부분에 대해 다음으로 가장 긴 일치를 시도하고 다시 시도합니다.

여기서 가장 긴 문자열과의 일치는 a1에 대한 .*것이므로 그룹 만 일치 2합니다. 그룹을 더 일찍 시작하려면 일부 정규 표현식 엔진을 사용하여 .*덜 욕심 을 만들 수 있지만 sed에는 그러한 기능이 없습니다. 따라서 추가 앵커로 모호성제거 해야합니다 . 행간 .*은 숫자로 끝날 수 없도록 지정 하여 그룹의 첫 번째 숫자가 첫 번째 가능한 일치가되도록하십시오.

  • 자릿수 그룹이 행의 시작 부분에없는 경우 :

    sed -n 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p'
    
  • 자릿수 그룹이 행의 시작 부분에있을 수 있고 sed가 \?옵션 부품에 대한 연산자를 지원하는 경우 :

    sed -n 's/^\(.*[^0-9]\)\?\([0-9][0-9]*\).*/\1/p'
    
  • 숫자 그룹이 줄의 시작 부분에있을 수 있다면 표준 정규 표현식 구조를 고수하십시오.

    sed -n -e 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p' -e t -e 's/^\([0-9][0-9]*\).*/\1/p'
    

그건 그렇고, 가장 긴 일치 규칙 [0-9]*은 후속 숫자가 아니라 첫 번째 숫자 다음의 숫자와 일치합니다 .*.

한 줄에 여러 자릿수의 시퀀스가 ​​있으면 프로그램은 initial에 적용된 가장 긴 일치 규칙으로 인해 항상 마지막 자릿수 시퀀스를 다시 추출합니다 .*. 첫 번째 숫자 시퀀스를 추출하려면 앞에 오는 숫자가 숫자가 아닌 시퀀스임을 지정해야합니다.

sed -n 's/^[^0-9]*\([0-9][0-9]*\).*$/\1/p'

보다 일반적으로 정규 표현식의 첫 번째 일치 항목을 추출하려면 해당 정규 표현식의 부정을 계산해야합니다. 이것이 이론적으로 항상 가능하지만 부정의 크기는 부정하는 정규 표현식의 크기에 따라 기하 급수적으로 증가하므로 종종 비현실적입니다.

다른 예를 고려하십시오.

sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p'

이 예제는 실제로 동일한 문제를 나타내지 만 일반적인 입력에서는 볼 수 없습니다. 당신이 그것을 먹이면 hello CONFIG_FOO_CONFIG_BAR위의 명령이 인쇄됩니다CONFIG_BAR 아니라CONFIG_FOO_CONFIG_BAR .

sed로 첫 번째 경기를 인쇄하는 방법이 있지만 약간 까다 롭습니다.

sed -n -e 's/\(CONFIG_[a-zA-Z0-9_]*\).*/\n\1/' -e T -e 's/^.*\n//' -e p

(sed가 대체 텍스트 \n에서 줄 바꿈을 의미 한다고 가정합니다 s.) 이것은 sed가 정규식의 가장 빠른 일치를 찾고 CONFIG_…비트 앞의 것을 일치시키지 않기 때문에 작동합니다 . 줄 안에 줄 바꿈이 없기 때문에 임시 줄로 사용할 수 있습니다. T앞 의 명령은s 명령이 일치하지 않으면 .

sed에서 무언가를 수행하는 방법을 알 수 없으면 awk로 전환하십시오. 다음 명령은 가장 빠른 정규 표현식 일치 항목을 인쇄합니다.

awk 'match($0, /[0-9]+/) {print substr($0, RSTART, RLENGTH)}'

간단하게 유지하려면 Perl을 사용하십시오.

perl -l -ne '/[0-9]+/ && print $&'       # first match
perl -l -ne '/^.*([0-9]+)/ && print $1'  # last match

22

그렇지 sed는 않지만 종종 간과되는 것 중 하나는 grep -o이 작업에 더 나은 도구라고 생각합니다.

예를 들어, CONFIG_커널 설정에서 모든 매개 변수 를 가져 오려면 다음을 사용하십시오.

# grep -Eo 'CONFIG_[A-Z0-9_]+' config
CONFIG_64BIT
CONFIG_X86_64
CONFIG_X86
CONFIG_INSTRUCTION_DECODER
CONFIG_OUTPUT_FORMAT

연속적인 숫자 시퀀스를 얻으려면 :

$ grep -Eo '[0-9]+' foo

7
sed '/\n/P;//!s/[0-9]\{1,\}/\n&\n/;D'

... n오른쪽 대체 필드에서 s 대신 리터럴 개행이 필요할 수 있지만 소란 없이이 작업을 수행 합니다. 그리고 .*CONFIG그건 그렇고, 한 줄에 일치하는 항목이있는 경우에만 작동합니다. 그렇지 않으면 항상 마지막 것만 얻습니다.

작동 방식에 대한 설명 은 이것을 볼 수 있지만 줄에서 발생하는 횟수만큼 일치하는 별도의 줄에 인쇄됩니다.

동일한 전략을 사용하여 [num]한 줄에서 발생 을 얻을 수 있습니다 . 예를 들어, CONFIG 일치를 한 줄에 세 번째로만 인쇄하려는 경우 :

sed '/\n/P;//d;s/CONFIG[[:alnum:]]*/\n&\n/3;D'

...하지만 가정 CONFIG 문자열이 각 발생에 대해 하나 이상의 영숫자가 아닌 문자로 분리되어 .

나는 수적으로-이것도 효과가 있다고 생각한다.

sed -n 's/[^0-9]\{1,\}/\n/g;s/\n*\(.*[0-9]\).*/\1/p

... 오른손에 대해 이전과 같은 경고로 \n. 이것은 첫 번째 것보다 빠르지 만 일반적으로 명백하게 적용 할 수는 없습니다.

CONFIG P;...;D의 경우 패턴과 함께 위 의 루프를 사용 하거나 다음을 수행 할 수 있습니다.

sed -n 's/[^C]*\(CONFIG[[:alnum:]]*\)\{0,1\}C\{0,1\}/\1\n/g;s/\(\n\)*/\1/g;/C/s/.$//p'

... 약간 더 복잡하고 sed참조 우선 순위를 올바르게 주문하여 작동합니다 . 또한 모든 CONFIG 일치 항목을 한 줄에 하나씩 분리합니다. 비록 이전과 동일하게 가정하지만 각 CONFIG 일치 항목은 적어도 하나의 영숫자가 아닌 문자로 구분됩니다. GNU sed를 사용하면 다음과 같이 작성할 수 있습니다.

sed -En 's/[^C]*(CONFIG\w*)?C?/\1\n/g;s/(\n)*/\1/g;/C/s/.$//p'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.