2

NOTE: I'm aware of this question: How to grep-inverse-match and exclude "before" and "after" lines. Mine is not a duplicate as had been previously cited, the answers to that question also deletes the pattern, while in this question the pattern itself must be preserved.


I am trying to delete n lines after a pattern and m lines before a pattern (without deleting pattern). For example, if the file is:

1
2
3
4
5
6
7
8
9

If, Pattern = 5, and n = 2 and m = 3. Then:

1
5
8
9

Could you please suggest how to do this?


Bonus: It would be great if we could set either m or n = 0 in the same code. For example. If we set m=0 and n=1, in the above example, we should get:

1
2
3
4
5
7
8
9
  • It is not duplicate as the cited link also deletes the pattern, while in this question pattern itself must be preserved. – Nikhil Oct 7 '18 at 15:29
3

To answer your general situation, we construct an appropriate ed code ahead of time based on the kind of inputs given.

 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

One way could be : this uses the ed editor to perform relative addressing as that is what your problem is centered around.

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

Explanation:

 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. 
  • Hi! Thanks it works. Could you please explain line 3, 4 and 5? I understand that /$re/ is pattern. What regex does this support? – Nikhil Oct 7 '18 at 9:15
  • Thanks for the explanation, can we make this code more versatile, such that it also works when either m or n are 0? – Nikhil Oct 7 '18 at 12:09
  • So in that scenario what's the output you expect. Fill that in the main body of this question. – Rakesh Sharma Oct 7 '18 at 12:52
  • I have updated the question, please look at the bottom. – Nikhil Oct 7 '18 at 15:30
2

Let's say you have a file - numbers.list:

1
2
3
4
5
6
7
8
9

Here's a script that should accomplish what you're after:

#!/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" )"

Example usage: ./matching.sh numbers.list 5 2 3

Note: This solution will not work as intended if expr evaluates negative values - up to you if you want to implement checks to avoid this behavior.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.