한 줄에 여러 번 나타나는 정규식에 대한 grep을 만드는 방법

한 줄에 여러 번 나타나는 정규식에 대한 grep을 만드는 방법

정규식을 grep하고 싶습니다. 내가 찾고 있는 패턴이 연속해서 여러 번 나타날 수 있습니다. 패턴이 여러 번 나타나는 경우 각 항목을 쉼표로 구분하여 인쇄하고 싶습니다.경쟁만새 파일에 완전한 줄이 없습니다. 인쇄하려는 줄에 나타나지 않는 경우

예. 이 정규식을 사용하여 [12.123.1.3] 패턴의 숫자를 찾고 싶습니다.

grep -oh "\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\]" 'filename'

입력 파일(input.txt)

blabla [11.335.2.33] xyuoeretrete [43.22.11.88] jfdfjkfbs [55.66.77.88]
blabla [66.223.44.33]
foo bar
blabla [1.2.33.3] xyuoeretrete [42] bla[1.32.2.4]

새 파일(output.csv)의 예상 결과:

11.335.2.33,43.22.11.88,55.66.77.88
66.223.44.33
n.a.
1.2.33.3,1.32.2.4

참고: 저는 Ubuntu를 사용합니다.

답변1

그리고 perl:

perl -lne '
  if (@ips = /\[(\d{1,3}(?:\.\d{1,3}){3})\]/g) {
    print join ",", @ips;
  } else {
    print "n.a.";
  }'

Regexp::Common또는 libregexp-common-perlUbuntu와 같은 Debian 기반 시스템의 패키지에서 점으로 구분된 쿼드 IPv4 주소에 대한 정규식을 사용합니다.

perl -MRegexp::Common=net -lne '
  if (@ips = /\[($RE{net}{IPv4})\]/g)
    print join ",", @ips;
  } else {
    print "n.a.";
  }'

를 사용하면 -nstdin에서 입력을 제공하고 경로가 추가 인수로 제공되는 파일에서 읽거나 와 같은 인수가 전달된 경우 일부 명령의 출력에서 ​​읽을 수 있습니다 some commands|. 기본적으로 stdout으로 인쇄 perl하며 , ( 추가) 또는 ( 파일이 먼저 잘리지 않고 읽기+쓰기 모드로 열리는 것을 제외하고) print과 같은 리디렉션 연산자를 사용하여 쉘에서 파일로 리디렉션할 수 있습니다 . 그리고 아마도 쉘에 따라 더 많을 수도 있습니다. .>>>1<>>

입력 파일의 내용을 궁극적으로 대체하는 출력 옵션을 추가할 수도 있습니다 -i(해당 경로는 인수로 제공되어야 함).

여기서 입력은 이름이 지정된 파일에서 가져와서 input.txt출력으로 파일을 덮어쓰거나 생성합니다.output.csv

< input.txt perl... > output.csv

답변2

FPAT에 GNU awk 사용:

awk -v FPAT='\\[([0-9]{1,3}[.]){3}[0-9]{1,3}\\]' -v OFS=, '
{
    $1=$1; print (gsub(/[][]/, "")?$0:"N/A")
}' <infile >output

또는 POSIX awk를 사용하십시오(모두 {x,y}RE 간격 지원).

awk '
{
    bkup=$0;
    gsub(/\[([0-9]{1,3}[.]){3}[0-9]{1,3}\]/, "|")
    gsub(/[][()\\.{}?+*$^]/, "\\\\&")
    n=split(bkup, tmp, $0)
    for(i=1; i<=n; i++){
        if(tmp[i]!=""){
            gsub(/[][]/, "", tmp[i])
            printf ("%s", (sep?",":"") tmp[i])
            sep=","
        }
    }; print (sep?"":"N/A"); sep=""
}' <infile >output

파일에 기록된 출력output.

$ cat output
11.335.2.33,43.22.11.88,55.66.77.88
66.223.44.33
N/A
1.2.33.3,1.32.2.4

두 번째 방법의 경우 입력에 |및 문자가 포함되어서는 안 됩니다.&


인라인 설명이 포함된 동일한 코드:

awk '
{
    #backup from the current record
    bkup=$0;

    #replace desired pattern all with "|" characters 
    #to build regexp patterns of everything other than our desired pattern
    gsub(/\[([0-9]{1,3}[.]){3}[0-9]{1,3}\]/, "|")

    #escape all regexp operators except "|"
    gsub(/[][()\\.{}?+*$^]/, "\\\\&")

    #split the original record (from bkup) into tmp on regexp
    # from the result of the first gsub() above
    n=split(bkup, tmp, $0)

    #loop through the splitted fields on the tmp array
    for(i=1; i<=n; i++){

        #if the current field is not empty
        if(tmp[i]!=""){

            #remove the ], [ characters from it
            gsub(/[][]/, "", tmp[i])

            #and print it (will add comma when it is the second or the next one)
            printf ("%s", (sep?",":"") tmp[i])

            #set comma as the field seperator when at least one field was printed
            sep=","
        }

    #print "N/A" in case there was no field and var "sep" did not set above
    # and then unset the "sep" var
    }; print (sep?"":"N/A"); sep=""

}' <infile >output

답변3

실행 가능한 awk 파일 filter.awk:

#! /usr/bin/awk -f
{
    ret = ""
    line = $0
    while (match(line, /\[([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}\]/) > 0) {
        if (ret != "") {
            ret = ret ","
        }
        ret = ret substr(line, RSTART, RLENGTH)
        line = substr(line, RSTART + RLENGTH)
    }
    if (ret != "") {
        print ret
    }
}

다음과 같이 실행하세요:

./filter.awk filename

답변4

사용행복하다(이전 Perl_6)

값 확인 없음:

raku -ne 'if m:g/ ( \d**1..3 )**4 % "." / { $/.join(",").put } else {"n.a.".say};'    

또는

raku -ne 'm:g/ ( \d**1..3 )**4 % "." / ?? $/.join(",").put !! "n.a.".say;'  

입력 예:

blabla [11.335.2.33] xyuoeretrete [43.22.11.88] jfdfjkfbs [55.66.77.88]
blabla [66.223.44.33]
foo bar
blabla [1.2.33.3] xyuoeretrete [42] bla[1.32.2.4]

샘플 출력(두 가지 예):

11.335.2.33,43.22.11.88,55.66.77.88
66.223.44.33
n.a.
1.2.33.3,1.32.2.4

적어도 Perl 언어 계열에서는 matchgrep이 아닌 을 원합니다. 따라서 "전역"이 일치의 여러 인스턴스를 반환 m/.../하도록 일치 연산자를 사용하십시오. 이는 전체 요소(예: 행 등)를 반환하는 grep과 다릅니다.m:g/.../포함하다경기].

\d**1..3즉, 각 인스턴스 사이에 마침표를 두고 **44번 반복되는 1~3개 숫자( )의 클러스터를 검색하고 이 정규식 일치( 또는 )를 전역적으로 검색합니다. 이는 모든 요소(행 등)에 대해 숫자의 A 일치를 얻는 것을 의미합니다. .) 첫 번째 일치뿐만 아니라 모든 인스턴스의 경우입니다. 첫 번째 예: find( ) 가 일치 변수 에 포함된 일치 하는 경우 ( 예 : . 두 번째 예: Raku의 삼항 연산자에 사용된 동일한 일치 조건, 즉 . 따라서 일치 변수 에 포함된 일치 항목은 조건이 (True)이거나 조건이 False 인 경우 출력됩니다 .% "."m:globalm:gifput$/elsen.a.condition ?? True !! False??put$/!!n.a.


아래 값을 확인하세요.

raku -ne 'if m:g/ ( \d**1..3 <?{ $/ < 256 }> )**4 % "." / { $/.join(",").put } else {"n.a.".say};'    

또는

raku -ne 'm:g/ ( \d**1..3 <?{ $/ < 256 }> )**4 % "." / ?? $/.join(",").put !! "n.a.".say;'  

입력 예: 위와 동일

샘플 출력(두 가지 예):

43.22.11.88,55.66.77.88
66.223.44.33
n.a.
1.2.33.3,1.32.2.4

위에 표시된 Raku 코드는 1~3자리의 각 클러스터를 검사하여 256. 추가 정규식 요소는 일치 변수가 256보다 작은지 확인하는 코드 블록을 <?{ $/ < 256 }>포함하는 긍정적인 어설션입니다 . 인용하다{...}$/여기.

https://raku.org

관련 정보