I can't find this case in the board, so I'm asking the question.
This is input file:
module
x(a,b,c)
module
y(d,e,f,
g,h,i)
module
z(j,k,l)
And output file should be:
module x(a,b,c)
module y(d,e,f,
g,h,i)
module z(j,k,l)
I can't find this case in the board, so I'm asking the question.
This is input file:
module
x(a,b,c)
module
y(d,e,f,
g,h,i)
module
z(j,k,l)
And output file should be:
module x(a,b,c)
module y(d,e,f,
g,h,i)
module z(j,k,l)
What you want to do is to join the module
lines with the next line.
Using sed
:
$ sed '/^module/N;s/\n//' file
module x(a,b,c)
module y(d,e,f,
g,h,i)
module z(j,k,l)
This is with your data copied and pasted as is, with spaces at the end of each line.
The sed
command will print each line as it is read, but when it encounters a line that starts with the string module
, it appends the next line with an embedded newline character in-between (this is what N
does). We remove that newline character with a substitution before the result is printed.
If your data has no spaces at the end of the lines, use
$ sed '/^module/N;s/\n/ /' file
module x(a,b,c)
module y(d,e,f,
g,h,i)
module z(j,k,l)
Just in case you'd want this (assuming no spaces at end of input lines):
$ sed -e '/^module/bpp' -e 'H;$bpp' -e 'd' \
-e ':pp' -e 'x;/^$/d;s/\n/ /g' file
module x(a,b,c)
module y(d,e,f, g,h,i)
module z(j,k,l)
Annotated sed
script:
/^module/ b print_previous; # print previous record
H; # append this line to hold space
$ b print_previous; # print previous (last) record
d; # end processing this line
:print_previous; # prints a record accumulated in the hold space
x; # swap in the hold space
/^$/ d; # if line is empty, delete it
s/\n/ /g; # replace embedded newlines by spaces
# (implicit print)
Bonus ed
content:
$ printf '%s\n' 'g/^module/ j' ,p Q | ed -s file
module x(a,b,c)
module y(d,e,f,
g,h,i)
module z(j,k,l)
The above joins any line starting with the string module
with its next line.
$ printf '%s\n' 'v/^module/ -,.j' ,p Q | ed -s file
module x(a,b,c)
module y(d,e,f, g,h,i)
module z(j,k,l)
The above joins any line not starting with the string module
with its previous line.
Using awk:
~ awk '/^module/ {l = $0; getline; printf "%s", l} 1' input-file
module x(a,b,c)
module y(d,e,f,
g,h,i)
module z(j,k,l)
For each line that starts with module
, save the line in l
, move to the next line (getline
), and print the saved line without a newline. Then print every line.
Another option: create an ed
script!
This starts by pre-counting the number of joins that are required; it then generates that number of ed
search & join commands and pipes them, along with a save & quit at the end, into ed
:
#!/bin/bash
n=$(grep -c '^module *$' input)
{
for((i=1; i <= n; i++))
do
printf '/^module *$/\n.,+1j\n'
done
echo w
echo q
} | ed -s input >/dev/null
Using Raku (formerly known as Perl_6)
~$ raku -ne '/^module/ ?? (print "$_\t"; put get) !! .put;' file
OR:
~$ raku -ne '/^module/ ?? (put join "\t", $_, lines[0]) !! .put;' file
The Raku answer above is similar to the excellent awk
answer by @muru. In Raku the ternary operator is spelled Test ??
True !!
False. The -ne
flags read the file linewise without autoprinting.
If the line starts with module
it is print
ed, followed by a \t
tab (this can be replaced with any column separator). Then (in the first example) the code instructs to get
the next line and put
it. In the second example you print the $_
topic variable, and take the next line line[0]
join on \t
and output
it. If no match to module
(i.e. "False"), the line is simply output
.
Sample Input (line-endings cleaned up):
module
x(a,b,c)
module
y(d,e,f,
g,h,i)
module
z(j,k,l)
Sample Output (tab-separated columns):
module x(a,b,c)
module y(d,e,f,
g,h,i)
module z(j,k,l)
Note the OP's input text contains trailing whitespace, so while using that raw input may be fine, other example text files that are to be concatenated might not contain trailing whitespace, in which case the "columns" will run-together. Hence the use of \t
above to space columns.