it-swarm-vi.tech

Cách chọn các dòng giữa hai mẫu đánh dấu có thể xảy ra nhiều lần với awk/sed

Sử dụng awk hoặc sed làm cách nào tôi có thể chọn các dòng xảy ra giữa hai mẫu đánh dấu khác nhau? Có thể có nhiều phần được đánh dấu với các mẫu này.

Ví dụ: Giả sử tệp chứa: 

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

Và mẫu bắt đầu là abc và mẫu kết thúc là mno Vì vậy, tôi cần đầu ra là: 

def1
ghi1
jkl1
def2
ghi2
jkl2

Tôi đang sử dụng sed để phù hợp với mô hình một lần: 

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

Có cách nào trong sed hoặc awk để làm điều đó nhiều lần cho đến khi kết thúc tập tin không? 

103
dvai

Sử dụng awk với cờ để kích hoạt in khi cần thiết:

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

Cái này hoạt động ra sao?

  • /abc/ khớp với các dòng có văn bản này, cũng như /mno/
  • /abc/{flag=1;next} đặt flag khi tìm thấy văn bản abc. Sau đó, nó bỏ qua dòng. 
  • /mno/{flag=0} bỏ cài đặt flag khi tìm thấy văn bản mno.
  • flag cuối cùng là một mẫu có hành động mặc định, đó là print $0: nếu flag bằng 1 thì dòng được in.

Để biết mô tả và ví dụ chi tiết hơn, cùng với các trường hợp khi các mẫu được hiển thị hoặc không, hãy xem Làm thế nào để chọn các dòng giữa hai mẫu? .

161
fedorqui

Sử dụng sed:

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

Tùy chọn -n có nghĩa là không in theo mặc định.

Mẫu tìm kiếm các dòng chỉ chứa abc để chỉ mno, sau đó thực hiện các hành động trong { ... }. Hành động đầu tiên xóa dòng abc; dòng thứ hai mno; và p in các dòng còn lại. Bạn có thể thư giãn các regexes theo yêu cầu. Bất kỳ dòng nào nằm ngoài phạm vi của abc..mno đơn giản là không được in.

38
Jonathan Leffler

Điều này có thể làm việc cho bạn (GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

Xóa tất cả các dòng ngoại trừ các dòng giữa các dòng bắt đầu abcmno

17
potong
sed '/^abc$/,/^mno$/!d;//d' file

golf hai nhân vật tốt hơn ppotong's{//!b};d

Dấu gạch chéo trống // có nghĩa là: "sử dụng lại biểu thức chính quy cuối cùng được sử dụng". và lệnh thực hiện giống như dễ hiểu hơn:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

Đây dường như là POSIX :

Nếu một RE trống (nghĩa là không có mẫu nào được chỉ định) thì sed sẽ hoạt động như thể RE cuối cùng được sử dụng trong lệnh cuối cùng được áp dụng (như là một địa chỉ hoặc là một phần của lệnh thay thế) đã được chỉ định.

Từ các liên kết của phản hồi trước đó, liên kết đã làm cho tôi, chạy ksh trên Solaris, là:

sed '1,/firstmatch/d;/secondmatch/,$d'
4
FanDeLaU

Câu trả lời của Don_crissti's từ Chỉ hiển thị văn bản giữa 2 mẫu phù hợp ?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

hiệu quả hơn nhiều so với ứng dụng của AWK, xem tại đây .

một cái gì đó như thế này làm việc cho tôi:

file.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

sử dụng: awk -f file.awk data...

chỉnh sửa: Giải pháp O_o fedorqui là cách tốt hơn/đẹp hơn của tôi.

1
pataluc
Perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
1
Vijay

Tôi đã cố gắng sử dụng awk để in các dòng giữa hai mẫu trong khi pattern2 cũng khớp với mẫu1 . Và dòng mẫu1 cũng nên được in. 

ví dụ . nguồn 

package AAA
aaa
bbb
ccc
package BBB
ddd
eee
package CCC
fff
ggg
hhh
iii
package DDD
jjj

nên có một thông số

package BBB
ddd
eee

Trong đó mẫu1 là package BBB, mẫu2 là package \w*. Lưu ý rằng CCC không phải là giá trị đã biết nên không thể khớp theo nghĩa đen.

Trong trường hợp này, cả awk '/abc/{a=1}/mno/{print;a=0}a' file và @fedorqui 's awk '/abc/{a=1} a; /mno/{a=0}' file của @scai đều không hoạt động với tôi.

Cuối cùng, tôi đã giải quyết nó bằng cách awk '/package BBB/{flag=1;print;next}/package \w*/{flag=0}flag' file, haha

Một nỗ lực nhiều hơn dẫn đến awk '/package BBB/{flag=1;print;next}flag;/package \w*/{flag=0}' file, để in dòng mẫu2, đó là,

package BBB
ddd
eee
package CCC
0
Weekend