I have the file "test" with the content in (1). I want a sed script, that edits "test" so that i have the output in (2).
I cannot not simply do this:
cat test | sed -E '1,/B/!{/U/,$!s/.+/# &/}'
...because it would start commenting out beginning from first 'B' and not from 'A\nB'.
(1)
X
X
B
A
B
X
X
X
U
U
V
X
X
(2)
X
X
B
A
B
# X
# X
# X
# U
U
V
X
X
Sed is Turing-complete, so you can do anything with it that you can do with any other programming language. Which means that you can have a complete solution to the original problem.
In fact, Sed has functions. Functions are just pieces of codes you can jump to and jump back from. The point is knowing where to jump to, forth and back. Setting :labels
, b
ranching to them or end of script unconditionally, or jumpting conditionally based on the result of a t
est is what allows you to write loop and functions in Sed.
Here's a relatively short one-liner accomplishing the original task.
sed '/A/{N;s/A\nB/&/;tc};b;:c;n;/U/{N;s/U\nV/&/;t};s/^./\# &/;s/\n/&\# /;bc' file
Let me explain using pseudo-code
/A/
: if line matches A
, do {
N
: append the next line to the current one;
s/A\nB/&/
: check if A\nB
matches (don't change it, just set the flag for the next t
command);
t
:est if the flag is set; if so, call the :c
ommenting function}
: otherwise,b
:ranch to end of script, i.e. print line as is and start over with the next line;
:c
:ommenting function:
n
, print what you have in pattern space and read the next line/U/
: if line matches U
, {
N
: append the next line to the current one;
s/U\nV/&/
: check if U\nV
matches (...);
t
: test if the flag is set and; if so, go to end of script, and start over with the next line, going out of the commenting code, }
s/^./\# &/
comment non-empty liness/\n\(.\)/&\# \1/
also comment non-empty line following a line match U
in case the former was not a V
b
ranch to :c
ommenting function, i.e. recursive call.