Reputation: 1135
My file contains lines like
GRANT SELECT ON USER.TABLE1 TO USER1
/
GRANT INSERT ON USER.TABLE1 TO USER1
/
GRANT UPDATE ON USER.TABLE1 TO USER1
/
GRANT DELETE ON USER.TABLE1 TO USER1
/
GRANT SELECT ON USER.TABLE1 TO USER2
/
GRANT INSERT ON USER.TABLE1 TO USER2
/
GRANT UPDATE ON USER.TABLE1 TO USER2
... and so on ...
The sed command I'm seeking, or better, the pattern, that crosses two lines, should delete the "GRANT .." line plus the subsequent line that's starting with the "/".
Any solutions from you sed gurus?
Upvotes: 0
Views: 115
Reputation: 204099
sed is for operations on single lines. For anything that spans lines you should use awk. e.g. with GNU awk for multi-char RS:
awk -v RS='^$' -v ORS= '{gsub(/GRANT[^\n]+\n[/]\n/,"")}1' file
e.g.:
$ cat file
foo
GRANT INSERT ON USER.TABLE1 TO USER1
/
GRANT UPDATE ON USER.TABLE1 TO USER1
intermediate line so leave
/
GRANT DELETE ON USER.TABLE1 TO USER1
/
bar
$ awk -v RS='^$' -v ORS= '{gsub(/GRANT[^\n]+\n[/]\n/,"")}1' file
foo
GRANT UPDATE ON USER.TABLE1 TO USER1
intermediate line so leave
/
bar
Upvotes: 0
Reputation: 44063
sed '/^GRANT/ { N; d }' filename
will, when it encounters a line beginning with GRANT
, fetch the next line and discard both.
To only remove GRANT
lines when the next line begins with /
,
sed ':a /^GRANT/ { N; /\n\//! { P; s/.*\n//; ba }; d }' filename
works. This is complicated mostly because of the possibility that two GRANT
lines come directly one after another, as in
GRANT foo
GRANT bar
/
where GRANT bar
and /
have to be removed and GRANT foo
to remain untouched:
:a # jump label for looping
/^GRANT/ { # if a line begins with GRANT
N # fetch the next line
/\n\//! { # if the next line does not begin with /
P # print the first
s/.*\n// # remove it
ba # go back to :a
}
d # otherwise discard both
}
Alternatively, using a multiline regex after reading the file completely into memory (assuming it fits there):
sed ':a $!{N; ba}; s/\(^\|\n\)GRANT[^\n]*\n\/[^\n]*//g' filename
where
:a $!{N; ba} # read whole file into the pattern space
s/\(^\|\n\)GRANT[^\n]*\n\/[^\n]*//g # match offending lines by regex and
# remove them
At this point, however, I feel that the sanest option is to use pcregrep
in muiltiline mode:
pcregrep -vM '^GRANT[^\n]*\n/' filename
Upvotes: 2
Reputation: 41460
This awk
should work:
awk '/^GRANT/ {f=1;next} f && /^\// {f=0;next} 1' file
If the line starting with ^GRANT
, skip it and set flag f
to true.
If line starts with /
and flag f
is true, skip it and reset flag f
1
print all other lines.
So this will only delete lines starting with GRANT
and the next line starting with /
Example:
cat file
GRANT SELECT ON USER.TABLE1 TO USER1
/
GRANT INSERT ON USER.TABLE1 TO USER1
test
/ should be removed
some other data
/ should not be removed
GRANT UPDATE ON USER.TABLE1 TO USER1
/
GRANT DELETE ON USER.TABLE1 TO USER1
/
GRANT SELECT ON USER.TABLE1 TO USER2
/
GRANT INSERT ON USER.TABLE1 TO USER2
/
GRANT UPDATE ON USER.TABLE1 TO USER2
awk '/GRANT/ {f=1;next} f && /^\// {f=0;next} 1' file
test
some other data
/ should not be removed
Upvotes: 0