stack
stack

Reputation: 841

How do I exclude a matching line and the line that precedes it?

In my project, I want to exclude some content in a.txt.

The content in a.txt is:

3085180 nscc135 PEND  intelg_sma gcn01                   *_D4d_5.sh Dec 14 14:32
The user has reached his/her job slot limit;
3085182 nscc135 PEND  intelg_sma gcn01                   *_C3v_5.sh Dec 14 14:32
The user has reached his/her job slot limit;
3085184 nscc135 PEND  intelg_sma gcn01                   *_C3v_5.sh Dec 14 14:33
The user has reached his/her job slot limit;
3085186 nscc135 PEND  intelg_sma gcn01                   *_D4d_5.sh Dec 14 14:33
The user has reached his/her job slot limit;
3095798 nsgg289 PEND  intelg_sma gcn03                   400./      Dec 19 09:51
One of the user's groups has reached its job slot limit;
3096822 nsgg289 PEND  intelg_sma gcn03                   460./      Dec 19 18:00
One of the user's groups has reached its job slot limit;
3098784 nsgg289 PEND  intelg_sma gcn04                   xhzha      Dec 20 14:48
One of the user's groups has reached its job slot limit;
3099298 nsgg276 PEND  intelg_sma gcn01                   Pd3.2      Dec 20 18:11
The user has reached his/her job slot limit;
3099299 nsgg276 PEND  intelg_sma gcn01                   Pd2.8      Dec 20 18:12
The user has reached his/her job slot limit;
3099311 nsgg276 PEND  intelg_sma gcn01                   Pt1.8      Dec 20 18:40
The user has reached his/her job slot limit;
3099312 nsgg276 PEND  intelg_sma gcn01                   Pt2        Dec 20 18:41
The user has reached his/her job slot limit;

I want to exclude this line containing the content of The user and the previous line. I have tried:

grep -A 1 -v "The\ user" a.txt

and

grep -AB 1 -v "The\ user" a.txt

But they both failed.

The correct result should be:

3095798 nsgg289 PEND  intelg_sma gcn03                   400./      Dec 19 09:51
One of the user's groups has reached its job slot limit;
3096822 nsgg289 PEND  intelg_sma gcn03                   460./      Dec 19 18:00
One of the user's groups has reached its job slot limit;
3098784 nsgg289 PEND  intelg_sma gcn04                   xhzha      Dec 20 14:48
One of the user's groups has reached its job slot limit;

Upvotes: 0

Views: 67

Answers (2)

leiyc
leiyc

Reputation: 973

It also works just using sed:

sed -e 'N;s/\n/####/;/The user/d' -e 's/####/\n/g' a.txt

Result:

3095798 nsgg289 PEND  intelg_sma gcn03                   400./      Dec 19 09:51
One of the user's groups has reached its job slot limit;
3096822 nsgg289 PEND  intelg_sma gcn03                   460./      Dec 19 18:00
One of the user's groups has reached its job slot limit;
3098784 nsgg289 PEND  intelg_sma gcn04                   xhzha      Dec 20 14:48
One of the user's groups has reached its job slot limit;

First, use N;s/\n/####/;/The user/d to combine two lines with ####, and delete line with The user; Then call s/####/\n/g to split the matched line to two lines.

Upvotes: 1

cody
cody

Reputation: 11157

I don't think -A and -B work the way you're expecting with -v. It will not "also exclude" the previous or next line. As such, I do not believe there is a solution to your problem using only grep.

One approach is to get the line numbers of the lines containing your pattern, and the lines immediately preceding them. Then, use sed to delete those line numbers:

grep -n -B 1 'The user' a.txt | egrep -v '^-' | sed -r 's/^([0-9]+).*/\1d/' | sed -f - a.txt

Result:

$ grep -n -B 1 'The user' a.txt | egrep -v '^-' | sed -r 's/^([0-9]+).*/\1d/' | sed -f - a.txt
3095798 nsgg289 PEND  intelg_sma gcn03                   400./      Dec 19 09:51
One of the user's groups has reached its job slot limit;
3096822 nsgg289 PEND  intelg_sma gcn03                   460./      Dec 19 18:00
One of the user's groups has reached its job slot limit;
3098784 nsgg289 PEND  intelg_sma gcn04                   xhzha      Dec 20 14:48
One of the user's groups has reached its job slot limit;

Explained:

grep -n -B 1 'The user' a.txt  # Print each line matching 'The user' and one line preceding it, the -n flag prefixes output with line number
egrep -v '^-'                  # The use of grep -B causes grep to separate match groups with '--', we want to disregard those lines
sed -r 's/^([0-9]+).*/\1d/'    # Extract the line numbers and with them create sed delete commands 
sed -f - a.txt                 # and finally feed those commands to sed, operating on your input file

Upvotes: 1

Related Questions