Chỉ trả lại phần của một dòng sau một mẫu phù hợp


109

Vì vậy, việc mở một tệp với catvà sau đó sử dụng grepđể có được các dòng khớp chỉ cho đến nay khi tôi làm việc với bộ nhật ký cụ thể mà tôi đang xử lý. Nó cần một cách để khớp các dòng với một mẫu, nhưng chỉ trả về phần của dòng sau khi khớp. Phần trước và sau trận đấu sẽ thay đổi liên tục. Tôi đã chơi bằng cách sử dụng sedhoặc awk, nhưng không thể tìm ra cách lọc dòng để xóa phần trước trận đấu, hoặc chỉ trả lại phần sau trận đấu, một trong hai sẽ hoạt động. Đây là một ví dụ về một dòng mà tôi cần lọc:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

Phần tôi cần là tất cả mọi thứ sau khi "bị đình trệ".

Bối cảnh đằng sau điều này là tôi có thể tìm hiểu mức độ thường xuyên một cái gì đó quầy hàng:

cat messages | grep stalled | wc -l

Điều tôi cần làm là tìm ra số lần một nút nhất định bị đình trệ (được biểu thị bằng phần trước mỗi dấu hai chấm sau khi "bị đình trệ". Nếu tôi chỉ grep cho điều đó (ví dụ 20 :) nó có thể trả về các dòng bị lỗi mềm, nhưng không có quầy hàng nào không giúp tôi. Tôi chỉ cần lọc phần bị đình trệ để sau đó tôi có thể grep cho một nút cụ thể trong số các nút bị đình trệ.

Đối với tất cả ý định và mục đích, đây là một hệ thống freebsd với các tiện ích lõi GNU tiêu chuẩn, nhưng tôi không thể cài đặt thêm bất cứ thứ gì để hỗ trợ.


@Gilles, Lạ là sao nó không bật lên khi tôi tìm kiếm, mặc dù tôi không sử dụng tiêu đề mà cuối cùng tôi đã đi cùng ... nhưng nó không hiển thị trong màn hình bên dưới tiêu đề của tôi. Dù sao, điều đó sang một bên, điều đó có thể đưa tôi đến nơi tôi muốn, mặc dù tôi cần toàn bộ dòng sau trận đấu, không phải từ đầu tiên - nhưng có thể không có nhiều thay đổi.
MaQleod

Tiêu đề của nó bị hút. Tôi đã đánh cắp của bạn đó là rất tốt đẹp. Lấy sedgiải pháp và không xử lý khoảng trắng đặc biệt.
Gilles

@Gilles, đó là điều tôi không hoàn toàn chắc chắn làm thế nào. Tôi vẫn đang học sed.
MaQleod

tương tự như unix.stackexchange.com/questions/24089/ cũng như vậy.
Tim Kennedy

1
@ shaa0601 Tôi không hiểu câu hỏi của bạn, đặc biệt khó theo dõi trong một nhận xét không có định dạng. Đặt một câu hỏi mới, khép kín.
Gilles

Câu trả lời:


141

Các công cụ kinh điển cho điều đó sẽ là sed.

sed -n -e 's/^.*stalled: //p'

Giải thích chi tiết:

  • -n có nghĩa là không in bất cứ thứ gì theo mặc định.
  • -e được theo sau bởi một lệnh sed.
  • s là lệnh thay thế mẫu.
  • Biểu thức chính quy ^.*stalled:khớp với mẫu bạn đang tìm, cộng với bất kỳ văn bản nào trước đó ( .*có nghĩa là bất kỳ văn bản nào, với chữ cái đầu tiên ^để nói rằng trận đấu bắt đầu ở đầu dòng). Lưu ý rằng nếu stalled:xảy ra nhiều lần trên dòng, điều này sẽ phù hợp với lần xuất hiện cuối cùng.
  • Trận đấu, tức là mọi thứ trên dòng lên đến stalled:, được thay thế bằng chuỗi trống (tức là đã xóa).
  • Phương ptiện cuối cùng để in dòng chuyển đổi.

Nếu bạn muốn giữ lại phần phù hợp, hãy sử dụng độ phản hồi: \1trong phần thay thế chỉ định những gì bên trong một nhóm \(…\)trong mẫu. Ở đây, bạn có thể viết stalled:lại trong phần thay thế; tính năng này hữu ích khi mẫu bạn đang tìm kiếm chung chung hơn một chuỗi đơn giản.

sed -n -e 's/^.*\(stalled: \)/\1/p'

Đôi khi bạn sẽ muốn xóa phần của dòng sau trận đấu. Bạn có thể đưa nó vào trận đấu bằng cách bao gồm .*$ở cuối mẫu (bất kỳ văn bản nào .*theo sau dòng cuối $). Trừ khi bạn đặt phần đó trong một nhóm mà bạn tham chiếu trong văn bản thay thế, phần cuối của dòng sẽ không nằm trong đầu ra.

Như một minh họa thêm về các nhóm và phản hồi, lệnh này hoán đổi phần trước trận đấu và phần sau trận đấu.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'

Tôi đã thử hai ví dụ đầu tiên và nó dường như bị treo. Tôi không nhận được thông báo lỗi, tôi cũng không nhận được lời nhắc mới, không có gì.
MaQleod

2
@MaQleod Ồ, nó đang chờ đầu vào trên đầu vào tiêu chuẩn, đây là thiết bị đầu cuối vì bạn chưa chuyển hướng nó. Ở đây bạn sẽ thực hiện chuyển hướng đầu vào sed … <messages, vì bạn muốn xử lý dữ liệu từ một tệp. Để hành động trên dữ liệu được tạo bởi một lệnh khác, bạn sẽ sử dụng một đường ống : somecommand | sed ….
Gilles

1
đúng rồi, cuối ngày mất điện ở đó. lệnh hoạt động hoàn hảo, cảm ơn.
MaQleod

1
Giải thích sed tốt nhất tôi đã thấy cho đến nay - cảm ơn!
Jon Wadsworth

1
@ungalcrys Phiên bản ngắn hơn của cái gì? Điều này không tương đương với bất kỳ lệnh nào trong câu trả lời của tôi. Tôi khuyên bạn nên viết nó như sed 's/^.*stalled//'kể từ khi -rlà cụ thể cho Linux và không hoạt động trên các hệ thống khác như hệ điều hành MacOS và ở đây bạn không nhận được bất kỳ lợi ích từ nó.
Gilles

72

Công cụ kinh điển khác mà bạn đã sử dụng grep::

Ví dụ:

grep -o 'stalled.*'

Có kết quả tương tự như tùy chọn thứ hai của Gilles:

sed -n -e 's/^.*\(stalled: \)/\1/p'

Các -ocờ trả về --only-matchingmột phần của biểu thức, vì vậy không phải toàn bộ dòng đó là - dĩ nhiên - thường được thực hiện bởi grep.

Để xóa "stalled:" khỏi đầu ra, chúng ta có thể sử dụng một công cụ chính tắc thứ ba, cắt:

grep -o 'stalled.*' | cut -f2- -d:

Các cutlệnh sử dụng dấu phân cách :và in trường 2 cho đến tận cùng. Tất nhiên đó là vấn đề ưu tiên, nhưng cutcú pháp tôi thấy rất dễ nhớ.


1
Cảm ơn đã đề cập đến các -otùy chọn! Tôi muốn chỉ ra rằng grepkhông nhận ra đây \nlà một dòng mới, vì vậy ví dụ đầu tiên của bạn chỉ khớp với nký tự đầu tiên . Ví dụ, echo "Hello Anne" | grep -o 'A[^\n]*'trả về chuỗi A. Tuy nhiên, echo "Hello Anne" | grep -o 'A.*'trả về dự kiến Anne, vì .phù hợp với bất kỳ nhân vật nào ngoại trừ dòng mới.
adamlamar

1
Lưu ý rằng các trích dẫn xung quanh cutdấu phân cách -d':'được xóa bởi @poige. Tôi thấy dễ nhớ hơn với dấu ngoặc kép, ví dụ với -d' 'hoặc -d';'.
Anne van Rossum

Theo tìm kiếm của bạn, nó sẽ dễ nhớ hơn để sử dụng dấu ngoặc kép -f 2quá. Nghiêm túc, tại sao không?
poige

Bởi vì một dấu phân cách như dấu chấm phẩy ;chứ không phải dấu hai chấm :sẽ được diễn giải khác nhau nếu không được trích dẫn. Tất nhiên đó là hành vi hợp lý, nhưng tôi vẫn thích dựa vào bộ nhớ cơ bắp. Tôi không muốn trích dẫn dấu phân cách một lần nhưng không phải lần khác. Chỉ là sở thích cá nhân, như tôi đã nói trước đây: dễ nhớ hơn.
Anne van Rossum

khoảng thời gian là một phần .*cần thiết, hoạt động tốt với tôi: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' lợi nhuậnxyz text
ron

4

Tôi đã từng ifconfig | grep eth0 | cut -f3- -d:lấy cái này

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

và làm cho nó trông như thế này

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8

2
Điều này có trả lời câu hỏi không?
Stephen Rauch

1
Bạn có thể sử dụng cat /sys/class/net/*/address, không cần phân tích cú pháp.
Anne van Rossum

1

Một công cụ kinh điển khác mà bạn xem xét awkcó thể được sử dụng với dòng sau:

awk -F"stalled" '/stalled/{print $2}' messages

Giải thích chi tiết:

  • -Fđịnh nghĩa một dấu phân cách cho dòng, nghĩa là "bị đình trệ". Tất cả mọi thứ trước khi phân tách được giải quyết với $1và tất cả mọi thứ sau với $2.
  • /reg-ex/ Tìm kiếm biểu thức chính quy phù hợp, trong trường hợp này là "bị đình trệ".
  • {print $<n>}- in n cột. Vì dấu phân cách của bạn được xác định là bị đình trệ, mọi thứ sau khi bị đình trệ được coi là cột thứ hai.
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.