Làm thế nào để thực hiện một grep nhiều dòng


15

Làm thế nào bạn sẽ thực hiện một grep cho văn bản xuất hiện trên hai dòng?

Ví dụ:

pbsnodes là một lệnh tôi sử dụng trả về việc sử dụng một cụm linux

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

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar

Tôi muốn xác định số lượng procs khớp với các nút ở trạng thái 'miễn phí'. Cho đến nay tôi đã có thể xác định "số lượng procs" và "các nút ở trạng thái tự do", nhưng tôi muốn kết hợp chúng thành một lệnh hiển thị tất cả các procs miễn phí.

Trong ví dụ trên, câu trả lời đúng sẽ là 6 (2 + 4).

Tôi có gì

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

Làm cách nào tôi có thể tìm kiếm mọi dòng đọc 'procs = x', nhưng chỉ khi dòng trên nó đọc 'state = free?

Câu trả lời:


12

Nếu dữ liệu luôn ở định dạng đó, bạn chỉ cần viết nó:

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

( RS=có nghĩa là hồ sơ là đoạn văn ).

Hoặc là:

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://en.wikipedia.org/wiki/Pipeline_(Unix)


4

Đây là một cách để làm điều đó bằng cách sử dụng pcregrep.

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

Thí dụ

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

3

Định dạng đầu ra của bạn được mồi cho đoạn văn bản của Perl:

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 }'

Ghi chú

Điều này chỉ hoạt động vì ý tưởng về "đoạn văn" của Perl là một đoạn gồm các dòng không trống được phân tách bằng một hoặc nhiều dòng trống. Nếu bạn không có các dòng trống giữa các nodephần, điều này sẽ không hoạt động.

Xem thêm


3

Nếu bạn có dữ liệu độ dài cố định (độ dài cố định liên quan đến số lượng dòng trong bản ghi), sedbạn có thể sử dụng Nlệnh (nhiều lần), nối dòng tiếp theo vào không gian mẫu:

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

sẽ cung cấp cho bạn đầu ra như:

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

Đối với thành phần bản ghi biến (ví dụ: với một dòng phân cách trống), bạn có thể sử dụng các lệnh phân nhánh tb, nhưng awkcó khả năng đưa bạn đến đó một cách thoải mái hơn.


3

Việc triển khai GNU grepđi kèm với hai đối số cũng in các dòng trước ( -B) và sau ( -A) khớp. Đoạn trích từ trang người đàn ông:

   -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.

Vì vậy, trong trường hợp của bạn, bạn sẽ phải grep cho state = freevà cũng in dòng sau. Kết hợp điều đó với đoạn trích từ câu hỏi của bạn, bạn sẽ đến một cái gì đó như thế:

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

và ngắn hơn một chút:

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

awkkhông khớp mẫu; bạn không cần grep: xem câu trả lời của Stephane
jasonwryan

Vâng, sedkhông phù hợp với mô hình là tốt. Bạn cũng có thể sử dụng perl, hoặc php, hoặc bất cứ ngôn ngữ nào bạn thích. Nhưng ít nhất tiêu đề của câu hỏi yêu cầu grep nhiều dòng ... ;-)
binfalse

Đúng: nhưng nhìn thấy bạn đang sử dụng awkdù sao ... :)
jasonwryan

0

... và đây là một giải pháp Perl:

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

0

Bạn có thể sử dụng awk getlinelệnh:

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

Từ 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.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.