Làm thế nào để đọc một số dòng nhất định sau khi tìm thấy một số văn bản?


12

Làm thế nào tôi có thể đọc một số dòng nhất định sau khi tìm thấy một số văn bản?

Ví dụ.:

Đọc 2 dòng tiếp theo sau khi tìm "Unix" trên:

Test 1
Test 2
Test 3
Test 4
UNIX
Test 5
Test 6
Test 7
Test 8
Test 9

Kết quả có thể là:

Test 5
Test 6

Lưu ý: "Unix" trong ví dụ trước là một đối số và do đó, nó có thể là bất kỳ văn bản nào khác.

Tôi có gì:

Tôi vẫn chưa có ý tưởng, chỉ cần một ánh sáng. Suy nghĩ về việc tạo ra một kịch bản khác để làm điều đó.

Câu trả lời:


10

Một awkgiải pháp:

$ awk '$0 == "UNIX" {i=1;next};i && i++ <= 2' file
Test 5
Test 6

Giải trình

  • /^UNIX$/{i=1;next}: nếu chúng ta thấy UNIX, chúng ta đặt biến i = 1, xử lý cho đầu vào tiếp theo.

  • Nếu biến iđược đặt (có nghĩa là chúng ta đã thấy UNIX), i && i++ <= 2chỉ được ước tính thành giá trị thực trong hai dòng tiếp theo sau UNIX, gây ra awkhành động mặc định được thực hiện print $0.

  • Trước khi nhìn thấy UNIX, ikhông được xác định và bắt đầu ở dòng thứ 3 sau UNIX, icó giá trị lớn hơn 2, điều này làm cho biểu thức được i && i++ <= 2ước tính là sai, awkkhông làm gì cả.


Sau khi kiểm tra, giải pháp của bạn tôi nhận được thông báo lỗi này: lỗi systax gần dòng 1 được bảo lãnh gần dòng 1
Lạnh

@Cold: Bạn đã chạy cái gì? Xin lưu ý rằng $dấu hiệu ở đầu câu trả lời của tôi là dấu nhắc shell, không phải là một phần của awklệnh.
cuonglm

Một biến thể khác:awk '/^UNIX$/ {s=NR;next} s && NR<=s+2'
musiphil

Tôi biết rằng @cuonglm
Lạnh

@Cold: HĐH của bạn là gì?
cuonglm

12

Một grepgiải pháp:

grep -A2 -P '^UNIX$' file

Giải thích: -A có nghĩa là: in hai dòng tiếp theo sau trận đấu

Hoặc là awk:

awk '$0=="UNIX"{getline; print; getline; print}' file

Giải thích: Câu lệnh đó tìm kiếm UNIX trong dòng ( $0=="UNIX"). Nếu được đưa ra, nó sẽ tiếp theo vào bộ đệm ( getline) và in bộ đệm ( print). Điều này được thực hiện hai lần.

Hoặc sử dụng sed:

sed -n '/^UNIX$/{n;p;n;p}' file

Giải thích: Đó là seaches cho UNIX ( /^UNIX$/). Nếu điều này được tìm thấy, nó txecutes phần trong {...}. ncó nghĩa là tiếp theo, pcó nghĩa là in. Điều này được thực hiện hai lần là tốt.


Cảm ơn @chaos, tôi sẽ thử 2 tùy chọn cuối cùng mà bạn đưa ra. Xin vui lòng nối một số giải thích của từng tùy chọn, tôi sẽ đồng ý và làm.
Lạnh

Nếu số lượng dòng thay đổi, tôi sẽ thực hiện bao nhiêu thay đổi trên hai tùy chọn cuối cùng? Cảm ơn
Lạnh

@Cold xem chỉnh sửa của tôi. Để thay đổi số nếu các dòng lặp lại getline; print;phần trong awkcâu lệnh hoặc n;p;phần trong sedcâu lệnh.
hỗn loạn

Cảm ơn @chaos, nhưng theo tôi, số lượng dòng tăng càng cao và sự thay đổi là không khả thi theo quan điểm của tôi. Bạn không nghĩ sao? Nếu 100 dòng?
Lạnh

@Cold Sau đó tôi sẽ sử dụng giải pháp grep với grep -A100 -P '^UNIX$' file | tail -n +2. Phần đuôi là để loại bỏ quyền cầm giữ đầu tiên. Trong những người khác (sed, awk) bạn sẽ phải viết các vòng lặp, điều gì làm cho nó ít đơn giản hơn.
hỗn loạn

4
grep -A 2 UNIX file.txt

Trang chủ của grep mô tả tùy chọn này:

  -A NUM, --after-context=NUM
      Print NUM  lines  of  trailing  context  after  matching  lines.
      Places  a  line  containing  --  between  contiguous  groups  of
      matches.

Xin chào @Twinkles, câu trả lời hay, nhưng grep của tôi chỉ có tùy chọn này "hblcnsviw". Nhưng logic là tốt. cảm ơn
Lạnh

Điều này cũng sẽ in UNIXở đầu ra.
cuonglm

Để bỏ qua UNIX, đặt nó vào tail: [...] | tail -n +1, hoặc sed: [...] | sed '1d'.
DopeGhoti

1
@DopeGhoti: chỉ tailvà các sed '1d'đề xuất của bạn chỉ hoạt động chính xác nếu UNIXchỉ xuất hiện một lần trong văn bản đầu vào. Tất cả các câu trả lời khác cho phép nhiều lần xuất hiện. Nó có thể tốt hơn để đề xuất ... | grep -v UNIX. Phải thừa nhận rằng điều này trở nên lộn xộn nếu UNIXxuất hiện trên các dòng 15 và 17.
G-Man nói 'Phục hồi Monica'

Điểm tốt. Tôi khá chắc chắn rằng nó chỉ có thể được thực hiện sedvới một số hình thức sed '/UNIX/d;n;n;p/' /path/to/file, mà tôi chỉ nói ra và gửi như một câu trả lời.
DopeGhoti

0

Điều này dường như để thực hiện các mẹo độc đáo:

sed -n '/UNIX/{n;p;n;p}' /path/to/file

Bằng chứng của khái niệm:

$ for i in {1..9}; do echo $i; done | sed -n '/4/{n;p;n;p}'
5
6

1
Subshell xung quanh forvòng lặp của bạn là không cần thiết.
Tạm dừng cho đến khi có thông báo mới.

Quả thực là không phải vậy; nó là tàn dư của một số faffery khác mà tôi đã ở giữa cái vỏ đó vào đầu ngày. Parens loại bỏ.
DopeGhoti

0

Bạn có thể sử dụng ex:

ex -s +'1,/UNIX/d|%p|q!' file_or_/dev/stdin

Ở đâu:

  • 1,/UNIX/d- xóa văn bản sau khi khớp
  • %p - in đệm
  • q!- thoát mà không lưu thay đổi vào tệp (sử dụng wqđể chỉnh sửa tại chỗ)
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.