Another sed:
sed -n '1x;1s/^/12345/;1x;G;:t
s/|\(.*\n)\(.\)/\2)\1/;tt
P' <infile >outfile
But probably awk
is more suitable here.
A much more complicated solution:
Given the output taken from your other question...
Question ipsun; option 1 | option 2 | option 3 | option 4 | ... | option n
Que|stion ipsun; option 1 | option 2 | option 3 | option 4 | ... | option n
...and passing that to...
sed ' s/^/!/;/|/s/\(.*;\)*[^|]*/&\
|/g; s/.*\(\n\).*/::::::\1&\1::/' |
nl -d:: -hp^\) -s\)\ |
sed -e' /./{ s/^ *!//;P;d;:n' -e'};N;/\n$/!bn
s/[0-9 ]*\n *\([^;|)]*) |*\)|/ (\1/g;D'
...to get...
Question ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)
Que|stion ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)
I guess I'll break it down...
sed ' s/^/!/;/|/s/\(.*;\)*[^|]*/&\
)/g; s/.*\(\n\).*/::::::\1&\1::/' |..
.
... is the first stage. This preps output for nl
.
nl
has a unique feature among the standard utilities - (the majority of which treat an entire input stream as a single, cohesive unit) - in that it can logically separate an input file by section. nl
will divide input into a header, body, and footer for each logical page of it. For the three sections per page a user might specify different number styles for each, and for each logical page the user can receive a new line count.
With sed
above I do:
s/^/!/
- If nothing else, this ensures that
nl
's section delimiter cannot occur in input accidentally, but this will also serve as a marker for trimming nl
's leading blanks on the other side of its processing.
/|/s...
- This only attempts to apply a substitution to a line which definitely matches at least one
|
pipe.
...s/\(.*;\)*[^|]*/&\n|/g
- This applies a global substitution against a pattern that can match anything (even nothing) but a
|
pipe which is not followed by at some point by a ;
semicolon.
- Because the
\(.*;\)*
is matched *
zero-or-more times, it matches the null-string most of the time. But the first time the matcher applies the sub-expression on a line which contains at least one ;
semicolon, then the entire range of pattern space from the head of the line through to the last semicolon on the line is effectively skipped.
- The point of this is to avoid matching any
[^|]*
sub-strings that occur before the dividing semicolon, and thus to skip the Question portion of your string entirely.
- For every occurrence of this pattern it is substituted for
&
itself, plus an appended \n|
.
s/.*\(\n\).*/::::::\1&\1::/
- This substitutes all of any pattern space which contains at least one
\n
ewline for six colons, then our captured \1\n
ewline, then &
itself, then our captured \1\n
ewline again, then two colons.
- I will be using the string
::
as nl
's section -d
elimiter. One of these strings begins an nl
footer section, and three of these strings marks a header - and a new logical page.
nl
will only recognize the delimiter if it occurs on a line all alone.
...and at this point the data stream looks like...
::::::
!Question ipsun; option 1
|| option 2
|| option 3
|| option 4
|| ...
|| option n
|
::
::::::
!Que|stion ipsun; option 1
|| option 2
|| option 3
|| option 4
|| ...
|| option n
|
::
...and now we can pass that through...
...|nl -d:: -hp^\) -s\)\ |...
-d::
- This specifies the
::
delimiter string.
nl
will replace every -d
elimiter string in input with a blank line on output.
nl
will either insert numbers at the head of its output lines, or it will insert spaces to match the length of its number string at the head of lines which it does not number.
- And so the only lines in its output which are ever blank are those which used to be its delimiter strings.
-hp^\|
- This is a
-h
eader style meaning number all lines which match the regex pattern.
nl
will be in a header state for each sequence of lines occurring between one containing only ::::::
and another containing only ::
.
- By default
nl
numbers only body sections and doesn't number headers or footers at all.
-s\)\
- This is a separator string which
nl
will insert between the head of each line it numbers and the number it inserts before it.
...and at this point the data stream looks like...
!Question ipsun; option 1
1) || option 2
2) || option 3
3) || option 4
4) || ...
5) || option n
6) |
!Que|stion ipsun; option 1
1) || option 2
2) || option 3
3) || option 4
4) || ...
5) || option n
6) |
...and last we can handle that with...
sed -e' /./{s/^ *!//;P;d;:n' -e '};N;/\n$/!bn
s/[0-9 ]*\n *\([^;|)]*) |*\)|/ (\1/g;D'
/./{...
- On any line containing at least one character this begins a match-focused function.
- Several commands may follow, but will only apply to pattern spaces which first matched the function's parent address.
...{s/^ *!//
- Here we trim all of
nl
's inserted blanks and our inserted bang from the head of matching lines.
P;d;:n
- This
P
rints up to the first \n
ewline in pattern space.
- Then
d
eletes pattern space.
- Then defines the branch label
:n
.
- From this point on we're only working with a sequence of lines which began with a blank one.
N
- This pulls in the
N
ext input line and appends it pattern space following a \n
ewline character.
/\n$/!bn
- While the pattern space does not
$
end with a \n
ewline - as it will be if the N
ext line is blank - we b
ranch back to the :n
label - stacking input all the while.
s/[0-9 ]*\n *\([^;|)]*) |*\)|/ (\1/g'
- This is a
g
lobal substitution.
- It replaces every sequence of...
*
zero-or-more [0-9 ]
chars
- followed by a
\n
ewline
- followed by
*
zero-or-more <spaces>
- followed by
*
zero-or-more ^
not colon or pipe chars
- followed by a right
)
paren
- possibly followed by a
|
pipe
- definitely followed by a
|
pipe
- with just the
^
not colon/pipe chars, right paren, and possible pipe.
D
- And now we
D
elete up to the first \n
ewline in pattern space (which is the very first character, since this sequence began with a blank line) and send the rest back to the top of the script to get the spaces and bang trimmed and P
rinted in the next new cycle.
The end result is:
Question ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)
Que|stion ipsun; option (1) | option (2) | option (3) | option (4) | ... (5) | option n (6)