SED: 패턴 매칭 후 5줄 위, 아래 4줄 삭제

SED: 패턴 매칭 후 5줄 위, 아래 4줄 삭제

다음 세부 정보가 포함된 휴 파일이 있습니다.

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
        }

제가 원하는 것은 "address 172.29.16.102"5줄 위, 4줄 뒤의 4줄을 찾아서 삭제하는 것입니다.

sed를 사용해 보았지만 작동하지 않습니다

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

답변1

이것은 각 define_host부분이 하나 이상의 줄 바꿈으로 구분되는 경우 GNU awk에서 발생하는 문제 유형과 정확히 같습니다.여러 줄의 레코드지원은 해결을 위한 것이다

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

답변2

이런 질문을 보면 직감적으로 이것이 직업이라고 생각합니다 grep. 그러나 앞으로 및 뒤로 스위치( & )를 사용할 때 결과를 반전( )하는 기능은 grep이를 허용하지 않습니다.-v-B ..-A ..

grep그러나 이를 두 번 호출하는 이 영리한 접근 방식은 지금까지 본 어떤 솔루션보다 awk훨씬 깔끔 합니다.sed

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

다음은 몇 가지 샘플 데이터입니다.

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

이제 다음 명령을 실행하면:

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

답변3

sed이유 에 대한 완벽한 예는 다음과 같습니다 .에스트레메편집하다exitor이며 내부 파일 편집 기능을 결코 대체하지 않습니다.

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

이 명령은 단순화된 형식이고 강력하지는 않지만 설명을 위해 사용됩니다.

첫 번째 명령은 지정된 정규식을 찾고 커서를 해당 줄로 이동합니다.

두 번째 명령은 delete 명령이 실행되는 두 개의 쉼표로 구분된 주소로 구성됩니다. ?{?현재 줄에서 뒤로 여는 중괄호를 검색하고 /}/현재 줄에서 앞으로 닫는 중괄호를 검색합니다. 그 사이의 모든 내용이 삭제됩니다(한 줄씩, 여는 중괄호 줄의 시작 부분도 삭제됨).

x변경 사항을 저장하고 종료합니다. 물론 input파일 이름입니다.

이 명령은 제공한 입력에 대해 예상한 대로 정확하게 작동합니다.


이제 저는 이것이 크게 개선될 수 있다고 언급했습니다. 정규식부터 시작하겠습니다. 여기서 가장 눈에 띄는 특징은 마침표가 와일드카드 문자라는 것입니다. 주어진 정규식은 "172329-16 103"과도 일치할 수 있습니다. 따라서 마침표는 리터럴 마침표와만 일치하도록 백슬래시로 이스케이프해야 합니다.

다음은 공백입니다. 두 개의 공백 뒤에 *가 있습니다(사용할 수 있지만 \+POSIX에 해당 기능이 필요한지 여부는 알 수 없음). 파일에 탭이 있으면 어떻게 됩니까? 가장 좋은 해결책은 를 사용하는 것입니다 [[:space:]]. (이것이 더 좋아 보일 것입니다 \+. 이것이 POSIX인지 알아낸 사람이 있으면 댓글을 남겨주세요.)

마지막으로 정규식이 다음과 같은 경우아니요파일에서 찾았나요? 그러면 파일이 편집을 위해 열리게 되고, "검색" 명령이 실패하고 오류 메시지가 인쇄되며, 주어진 명령의 나머지 부분은 실행되지 않습니다. 편집기에 남아서 검색할 수 있습니다 ex. 수동으로 변경됩니다. 그러나 스크립트 편집을 자동화하려면 편집기가 필요할 수 있습니다.출구변경이 필요하지 않은 경우. 대답은 g전역 명령을 사용 하고 이 -s플래그를 사용하여 모든 출력을 억제하는 것입니다 ex.

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

이것은 아니다상당히이전 명령과 동일합니다. 일치하는 줄이 있는 중괄호 블록이 여러 개 있는 경우 여기의 전역 명령은 해당 블록을 모두 제거합니다. 어쨌든 이것은 아마도 당신이 원하는 것일 것입니다.

첫 번째 일치 항목만 삭제하고 일치 항목이 전혀 없으면 파일을 변경하지 않고 종료하려면 이 x명령을 명령 인수의 일부로 사용하고 g(첫 번째 삭제 명령을 실행한 후 파일 종료) 다음 q!위치에 명령을 추가하면 됩니다. g일치하는 줄이 누락되어 명령이 실행되지 않는 경우를 대비해 맨 아래에 표시됩니다 .

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

솔직히 이러한 명령은 프로세스를 실제보다 훨씬 더 복잡하게 보이게 만듭니다. 견고성은 코드의 극도의 명확성과 가독성을 희생하면서 발생합니다. 이것은 절충안입니다.

ex느낌을 얻으 려면 일부 파일을 대화식으로 편집하는 것이 좋습니다 . 그래서 당신은 할 수 있습니다바라보다뭐하세요. 이 수정 사항을 대화식으로 수행하는 편집 세션은 ex다음과 같습니다.

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

이것POSIX 사양ex추가 자료가 제공됩니다.

답변4

이건 어때?

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

파일에 유사한 줄이 없다고 가정하면 필요하지 않은 특정 줄을 제거합니다.

관련 정보