멀티 라인 그렙을 수행하는 방법


15

두 줄로 표시되는 텍스트에 대해 grep을 어떻게 수행 하시겠습니까?

예를 들면 다음과 같습니다.

pbsnodes 리눅스 클러스터의 사용률을 반환하는 명령입니다

root$ pbsnodes
node1
    state = free
    procs = 2
    bar = foobar

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar

상태가 'free'인 노드와 일치하는 프로세스 수를 결정하고 싶습니다. 지금까지 "프로 크 수"와 "자유 상태의 노드"를 확인할 수 있었지만 모든 무료 프록을 표시하는 하나의 명령으로 결합하고 싶습니다.

위의 예에서 정답은 6 (2 + 4)입니다.

내가 가진 것

root$ NUMBEROFNODES=`pbsnodes|grep 'state = free'|wc -l`
root$ echo $NUMBEROFNODES
2

root$ NUMBEROFPROCS=`pbsnodes |grep "procs = "|awk  '{ print $3 }' | awk '{ sum+=$1 } END { print sum }'`
root$ echo $NUMBEROFPROCS
14

'procs = x'를 읽는 모든 줄을 어떻게 검색 할 수 있습니까?하지만 위의 줄이 'state = free'인 경우에만 가능합니까?

답변:


12

데이터가 항상 해당 형식 인 경우 간단히 다음과 같이 작성할 수 있습니다.

awk -vRS= '$4 == "free" {n+=$7}; END {print n}'

( 레코드가 단락RS= 임을 의미 합니다 ).

또는:

awk -vRS= '/state *= *free/ && match($0, "procs *=") {
  n += substr($0,RSTART+RLENGTH)}; END {print n}'

5
$ pbsnodes
node1
    state = free
    procs = 2
    bar = foobar

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar
$ pbsnodes | grep -A 1 free
    state = free
    procs = 2
--
    state = free
    procs = 4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}'
2
4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+ 
2+4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+ | bc 
6

https://ko.wikipedia.org/wiki/Pipeline_ (유닉스)


4

를 사용하여 수행하는 한 가지 방법이 있습니다 pcregrep.

$ pbsnodes | pcregrep -Mo 'state = free\n\s*procs = \K\d+'
2
4

$ pbsnodes | \
    pcregrep -Mo 'state = free\n\s*procs = \K\d+' | \
    awk '{ sum+=$1 }; END { print sum }'
6

3

출력 형식은 Perl의 단락 slurp에 대해 준비되었습니다.

pbsnodes|perl -n00le 'BEGIN{ $sum = 0 }
                 m{
                   state \s* = \s* free \s* \n 
                   procs \s* = \s* ([0-9]+)
                 }x 
                    and $sum += $1;
                 END{ print $sum }'

노트

이것은 "단락"에 대한 Perl의 아이디어가 하나 이상의 빈 줄로 분리 된 비 공백 줄의 덩어리이기 때문에 작동합니다. node섹션 사이에 빈 줄 이 없다면 이것은 효과가 없을 것입니다.

또한보십시오


3

고정 길이 데이터 (레코드의 행 수를 참조하는 고정 길이 )가있는 경우 다음 행을 패턴 공간에 결합하는 명령 (여러 번)을 sed사용할 수 있습니다 N.

sed -n '/^node/{N;N;N;s/\n */;/g;p;}'

다음과 같은 출력을 제공해야합니다.

node1;state = free;procs = 2;bar = foobar
node2;state = free;procs = 4;bar = foobar
node3;state = busy;procs = 8;bar = foobar

변수 기록 구성 (예 : 빈 분리 라인)의 경우, 분기 명령의 사용을 만들 수 tb하지만 awk당신이 더 편안한 방법으로 얻을 가능성이 높습니다.


3

GNU 구현 에는 일치 grep전 ( -B)과 이후 ( -A)를 인쇄하는 두 개의 인수가 있습니다 . 매뉴얼 페이지의 스 니펫 :

   -A NUM, --after-context=NUM
          Print NUM lines of trailing context after matching lines.  Places a line containing  a  group  separator  (--)  between  contiguous  groups  of  matches.   With  the  -o  or
          --only-matching option, this has no effect and a warning is given.

   -B NUM, --before-context=NUM
          Print  NUM  lines  of  leading  context  before  matching  lines.   Places  a  line  containing  a group separator (--) between contiguous groups of matches.  With the -o or
          --only-matching option, this has no effect and a warning is given.

따라서 귀하의 경우 state = free다음 줄 을 grep 하고 인쇄해야합니다. 그것을 당신의 질문의 스 니펫과 결합하면 다음과 같은 것에 도달 할 것입니다 :

usr@srv % pbsnodes | grep -A 1 'state = free' | grep "procs = " | awk  '{ print $3 }' | awk '{ sum+=$1 } END { print sum }'
6

그리고 조금 더 짧습니다 :

usr@srv % pbsnodes | grep -A 1 'state = free' | awk '{ sum+=$3 } END { print sum }'
6

awk패턴 일치를 수행합니다. 당신은 필요하지 않습니다 grep: Stephane의 답변
jasonwryan

음, sed물론 패턴 매칭을 수행합니다. perl또는 php, 또는 원하는 언어를 사용할 수도 있습니다 . 그러나 적어도 질문의 헤드 라인은 멀티 라인 grep을 요청 ...
...-)

네 :하지만 당신이 사용하고보고 awk... :) 어쨌든
jasonwryan

0

... 그리고 여기 Perl 솔루션이 있습니다 :

pbsnodes | perl -lne 'if (/^\S+/) { $node = $& } elsif ( /state = free/ ) { print $node }'

0

다음 awk getline명령을 사용할 수 있습니다 .

$ pbsnodes | awk 'BEGIN { freeprocs = 0 } \
                  $1=="state" && $3=="free" { getline; freeprocs+=$3 } \
                  END { print freeprocs }'

보낸 사람 man awk :

   getline               Set $0 from next input record; set NF, NR, FNR.

   getline <file         Set $0 from next record of file; set NF.

   getline var           Set var from next input record; set NR, FNR.

   getline var <file     Set var from next record of file.

   command | getline [var]
                         Run command piping the output either into $0 or var, as above.

   command |& getline [var]
                         Run  command  as a co-process piping the output either into $0 or var, as above.  Co-processes are a
                         gawk extension.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.