SED: Xóa 4 dòng trên và dưới 5 dòng sau khi khớp mẫu


7

Tôi có tập tin Hugh với các chi tiết sau:

define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerA_172.29.16.102
        alias                   ServerA_172.29.16.102
        address                 172.29.16.102
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }



define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerB_172.29.16.103
        alias                   ServerB_172.29.16.103
        address                 172.29.16.103
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

Những gì tôi muốn, Tìm kiếm "address 172.29.16.102"và Xóa 4 dòng trên và sau 5 dòng.

Tôi đã thử làm theo với sed nhưng không hoạt động

sed '$N;$N;N;/address                 172.29.16.102/,+5d' hosts

PHẢI nó là sed, hoặc bạn đang mở cho các công cụ khác?
ghoti

Nếu bạn đang xóa cả 4 dòng trước VÀ 5 sau, chắc chắn sed -n '/\s*address/p;' filesẽ giải quyết nó? Cái nào giống cái grep 'address' filenào? Hay tôi đang thiếu một cái gì đó ở đây? Đầu ra có nghĩa là gì?
Drav Sloan

Có bất kỳ entry nhiều trong tập tin đầu vào, tôi chỉ muốn loại bỏ một số phương tiện container từ define {để }nếu điều đó phù hợp với địa chỉ, Nó không nên loại bỏ bất kỳ nội dung khác, đó là nó
Rahul Patil

Câu trả lời:


7

Nếu mỗi define_hostphần được phân tách bằng một hoặc nhiều dòng mới, thì đây chính xác là loại vấn đề hỗ trợ bản ghi nhiều dòng của GNU awk có nghĩa là để giải quyết

awk -v RS= '!/172.29.16.102/{printf $0""RT}'

Tôi sẽ chấp nhận điều này, bạn có thể vui lòng giải thích nó. cảm ơn ..
Rahul Patil

Điều này cũng không hoạt động, những điều rất kỳ lạ xảy ra, điều này cũng loại bỏ các mục khác không liên quan ..
Rahul Patil

@RahulPatil, thú vị. Có phải mục khác xảy ra để chứa 172.29.16.102? Ngoài ra, nó đã được phân tách rõ ràng với các mục khác bằng các dòng trống?
iruvar

Không, không liên quan đến điều đó
Rahul Patil

4

Khi tôi thấy loại câu hỏi này, ruột của tôi nói với tôi rằng đây là một công việc grep. Tuy nhiên grep, khả năng đảo ngược ( -v) kết quả khi sử dụng các công tắc trước & sau ( -B ..& -A ..) không cho phép điều này.

Tuy nhiên, cách tiếp cận thông minh này để gọi grep2 lần sẽ gọn gàng hơn bất kỳ giải pháp awkhoặc sedgiải pháp nào tôi từng thấy cho đến nay.

$ grep -v "$(grep -B 4 -A 5 'address 172.29.16.102' <file>)" <file>

Thí dụ

Đây là một số dữ liệu mẫu.

$ cat sample.txt
define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerA_172.29.16.102
        alias                   ServerA_172.29.16.102
        address                 172.29.16.102
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

line1b
line2b
line3b
line4b
address 172.29.16.102
line5a
line4a
line3a
line2a
line1a

define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerB_172.29.16.103
        alias                   ServerB_172.29.16.103
        address                 172.29.16.103
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

Bây giờ khi chúng tôi chạy lệnh của chúng tôi:

$ grep -v "$(grep -B 4 -A 5 'address 172.29.16.102' sample.txt)" sample.txt
define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerA_172.29.16.102
        alias                   ServerA_172.29.16.102
        address                 172.29.16.102
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }


define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerB_172.29.16.103
        alias                   ServerB_172.29.16.103
        address                 172.29.16.103
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

Điều này hoạt động tốt cho OP; tuy nhiên, trong trường hợp chung, có một vấn đề khi các dòng khớp chứa các ký tự dành riêng regex.
Andrew Hows

Điều này cũng không hoạt động trong trường hợp chung trong đó các dòng cần xóa, những dòng trước và sau dòng trùng khớp, không phải là duy nhất trong tệp và các bản sao khác không nên bị xóa.
carandraug

2

Thay vì sử dụng số lượng dòng nghiêm ngặt với sed hoặc grep, sở thích của tôi sẽ là viết một cái gì đó diễn giải cơ bản định dạng tệp và đánh giá nội dung của từng bản ghi . Hãy xem xét những điều sau bằng cách sử dụng awk:

#!/usr/bin/awk -f

function doit(blob) {
  if (blob !~ /address[[:space:]]+172\.29\.16\.102/) {
    print blob;
  } 
}

# Find a new record...
/^define host/ {
  doit(blob);
  blob="";
}

# Don't start each record with a blank line...
length(blob) { blob=blob "\n"; }

# Collect our data...    
{ blob=blob $0; }

END {
  doit(blob);
}

Ý tưởng ở đây là chúng ta sẽ duyệt qua tệp và mỗi lần chúng ta thấy define hostchúng ta sẽ bắt đầu tiếp tục thêm từng dòng vào biến blob. Khi một bản ghi mới bắt đầu hoặc khi chúng ta đến cuối tệp, chúng ta xử lý biến đó bằng doit()hàm.

Điều này hoạt động trong cả GNU và awk cổ điển.


2

Đây là một ví dụ hoàn hảo về việc tại sao seds tream ed itor, và sẽ không bao giờ thay thế sức mạnh của exđể chỉnh sửa tập tin tại chỗ.

ex -c '/address  *172.29.16.103/
?{?,/}/d
x' input

Lệnh này là một hình thức đơn giản hóa không mạnh mẽ như nó có thể, nhưng phục vụ cho việc minh họa.

Lệnh đầu tiên tìm regex được chỉ định và di chuyển con trỏ đến dòng đó.

Lệnh thứ hai bao gồm hai địa chỉ được phân tách bằng dấu phẩy, trên đó dlệnh elete được chạy. ?{?tìm kiếm ngược từ dòng hiện tại cho một dấu ngoặc nhọn mở và /}/tìm kiếm chuyển tiếp từ dòng hiện tại cho một dấu ngoặc nhọn gần. Tất cả mọi thứ ở giữa sẽ bị xóa (theo chiều dọc, do đó, phần đầu của dòng dấu ngoặc nhọn mở cũng bị xóa).

xlưu các thay đổi và lối thoát. Và inputtất nhiên là tên của tập tin.

Đối với đầu vào bạn đã đưa ra, lệnh này hoạt động chính xác như mong muốn.


Bây giờ, tôi đã đề cập đến điều này có thể được cải thiện đáng kể. Chúng ta sẽ bắt đầu với regex. Sự rõ ràng nhất ở đây là thời gian là ký tự đại diện; regex như đã cho cũng có thể phù hợp với "172329-16 103". Vì vậy, các khoảng thời gian phải được thoát với dấu gạch chéo ngược để chúng chỉ khớp với các khoảng thời gian theo nghĩa đen.

Tiếp theo là khoảng trắng. Tôi đặt hai dấu cách theo sau là dấu * (tôi có thể đã sử dụng \+nhưng tôi không biết tính năng đó có bắt buộc trong POSIX không), nhưng nếu có các tab trong tệp thì sao? Giải pháp tốt nhất là sử dụng [[:space:]]. (Điều này sẽ trông đẹp hơn nhiều với \+; nếu có ai tìm thấy liệu đó có phải là POSIX không, vui lòng gửi bình luận.)

Cuối cùng, nếu regex không được tìm thấy trong tập tin thì sao? Chà, sau đó, tệp sẽ được mở để chỉnh sửa và lệnh "tìm kiếm" sẽ thất bại và thông báo lỗi sẽ được in và phần còn lại của các lệnh đã cho sẽ không được thực thi - bạn sẽ bị bỏ lại trong extrình chỉnh sửa để bạn có thể thay đổi bằng tay. Tuy nhiên, nếu bạn muốn tự động hóa các chỉnh sửa trong tập lệnh, bạn có thể muốn trình chỉnh sửa thoát nếu không cần thay đổi. Câu trả lời là sử dụng glệnh lobal, và cũng sử dụng -scờ để chặn bất kỳ đầu ra nào từ ex:

ex -sc 'g/address[[:space:]][[:space:]]*172\.29\.16\.103/ ?{?,/}/d
x' input

Điều này không hoàn toàn tương đương với lệnh trước đó; nếu có nhiều hơn một khối dấu ngoặc nhọn có một đường khớp, lệnh toàn cục ở đây sẽ xóa tất cả. Đó có lẽ là những gì bạn muốn anyway.

Nếu bạn chỉ muốn xóa trận đấu đầu tiên, trong khi thoát mà không thay đổi tệp nếu không có kết quả khớp nào, bạn có thể sử dụng xlệnh như một phần của đối số cho glệnh (để thoát tệp sau khi lệnh xóa đầu tiên được thực hiện) và ném một q!lệnh ở phía dưới trong trường hợp glệnh không thực thi vì thiếu bất kỳ dòng khớp nào.

ex -sc 'g/address[[:space:]][[:space:]]*172\.29\.16\.103/ ?{?,/}/d | x
q!' input

Thành thật mà nói, các lệnh này làm cho quá trình trông phức tạp hơn nhiều so với thực tế; sự mạnh mẽ đến từ chi phí cực kỳ rõ ràng và dễ đọc của mã. Đó là một sự đánh đổi.

Tôi khuyên bạn nên chỉnh sửa một vài tệp tương tác exđể có cảm nhận về nó. Bằng cách đó bạn có thể thấy những gì bạn đang làm. Một phiên chỉnh sửa như vậy exđể thực hiện sửa lỗi này tương tác trông giống như thế này:

$ ex input
"input" 23L, 843C
Entering Ex mode.  Type "visual" to go to Normal mode.
:/103
        host_name               ServerB_172.29.16.103
:?{?,/}/d                             # This deletes the current block

:$p                                   # Print and move to last line

:-5,.p                                # Print some more lines to check result
        notification_interval   120
        notification_period     24x7
        }



:?}?+,.d                              # Trim whitespace
        }
:x                                    # Save and exit
$ 

Các thông số kỹ thuật POSIX đểex cung cấp đọc thêm.


0

Cái này thì sao?

egrep -v '^([[:space:]]+(use|host_name|alias|check_command|max_check_attempts|notification_interval|notification_period)[[:space:]]+|^define host{|^[[:space:]]+})'

Nó loại bỏ các dòng cụ thể không cần thiết, nếu chúng ta cho rằng những gì không có dòng tương tự trong tệp thì chúng ta không nên xóa.


0

Với sedbạn có thể làm:

sed -ne'/^[^ ]/!{H;$!d;}' <in >out \
    -e 'x;//{/\n *address  *172\.29\.16\.103/!p;}'

... sẽ đệm riêng từng khối trong Hkhông gian cũ khi chúng được đọc và chỉ in những khối không chứa khớp cho mẫu của bạn.

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.