패턴 뒤 n라인, 패턴 앞 m라인 삭제

패턴 뒤 n라인, 패턴 앞 m라인 삭제

노트: 나는 이 질문을 알고 있습니다:역방향으로 grep하고 "이전" 및 "이후" 줄을 ​​제외하는 방법. 내 것은 이전 인용문과 중복되지 않습니다. 해당 질문에 대한 답변도 패턴을 제거하는 반면, 이 질문에서는 패턴 자체가 남아 있어야 합니다.


패턴을 삭제하지 않고 패턴 뒤의 n 줄과 패턴 앞의 m 줄을 삭제하려고 합니다. 예를 들어, 파일이 다음과 같은 경우:

1
2
3
4
5
6
7
8
9

패턴 = 5이면 n = 2, m = 3입니다. 하지만:

1
5
8
9

이 작업을 수행하는 방법을 제안해 주실 수 있나요?


보너스: 같은 코드에서 m 또는 n = 0으로 설정할 수 있으면 좋을 것 같습니다. 예를 들어. 위의 예에서 m=0 및 n=1로 설정하면 다음과 같은 결과를 얻게 됩니다.

1
2
3
4
5
7
8
9

답변1

귀하의 일반적인 질문에 답하기 위해 우리는 ed주어진 입력 유형에 따라 적절한 코드를 미리 구축합니다.

 re=5 n=2 m=3
 code=$(
   prev="/$re/-$m,/$re/-1d"
   next="/$re/+1,/$re/+${n}d"
    case "$m/$n" in
       0/0) set -- ;;
       0/?*) set -- "$next" "w" ;;
       ?*/0) set -- "$prev" "w" ;;
         *) set -- "$prev" "$next" "w" ;;
    esac
    printf '%s\n' ${1+"$@"} "q" 
 ) 
 ed -s filename - <<eof
 $code
 eof

한 가지 접근 방식은 다음과 같습니다. ed편집기를 사용하여 상대 주소 지정을 수행합니다. 이것이 질문의 중심이기 때문입니다.

 n=3 m=2 re=5
 ed -s filename - <<eof
 /$re/-$m,/$re/-1d
 .+1,.+${n}d
 wq
 eof

설명하다:

 1. Line 3 after var substitution becomes
            /5/-2,/5/-1
      What it does is, sitting on line which satisfies the regex /5/, it looks 2 lines behind and stops looking 1 line before the /5/ line or the current line and deletes that bunch. Remember the current line is not deleted.

   2.  Line 4, after var sub becomes
                .+1,.+3d
       . is the nickname for the current line, which in our case is /5/
       So, starting fron one line after the current upto 3 lines after the current, delete them all. Note the current line is still untouched.

  3. Line 5 is wq which means save the modified file back onto itself and quit.

For more on info google the manual for gnu ed editor. 

답변2

다음과 같은 파일이 있다고 가정해 보겠습니다 numbers.list.

1
2
3
4
5
6
7
8
9

다음은 원하는 작업을 수행하는 스크립트입니다.

#!/bin/bash
if [ -z "$1" ]; then
    echo >&2 "error: no file specified"
    exit 1
fi
if [ ! -f "$1" ]; then
    echo >&2 "error: $1 is not a file"
    exit 1
fi
if [ -z "$2" ]; then
    echo >&2 "error: no pattern specified"
    exit 1
fi
grep "$2" "$1" >/dev/null 2>&1
if [ ! 0 -eq "$?" ]; then
    echo >&2 "error: pattern $2 not found in $1"
    exit 1
fi
MATCH_FILE="$1"
MATCH_PATTERN="$2"
MATCH_DELETE_AFTER=0
MATCH_DELETE_BEFORE=0
if [ ! -z "$3" ]; then
    MATCH_DELETE_AFTER="$3"
fi
if [ ! -z "$4" ]; then
    MATCH_DELETE_BEFORE="$4"
fi
MATCH_FILE_LINE="$( grep -n "$2" "$1" | cut -d: -f1 )"
#
# print matching `head` minus MATCH_DELETE_BEFORE lines
cat "$1" \
    | head -n "$( expr "$MATCH_FILE_LINE" - "$MATCH_DELETE_BEFORE" - 1 )"
#
# print matching line
cat "$1" \
    | head -n "$MATCH_FILE_LINE" \
    | tail -n 1
#
# print matching `tail` minus MATCH_DELETE_AFTER lines
cat "$1" \
    | tail -n "$( expr "$( wc -l "$1" | cut -d' ' -f1 )" - "$MATCH_FILE_LINE" - "$MATCH_DELETE_AFTER" )"

사용 예: ./matching.sh numbers.list 5 2 3

노트:expr음수 값이 계산되면 이 솔루션이 예상대로 작동하지 않습니다. 이 동작을 방지하기 위한 검사를 구현하려는지는 사용자에게 달려 있습니다.

관련 정보