how to merge next line to current line by keeping the next line

Viewed 507

I have this:

A abc
B abc
C abc
D abc
...

and I need to have such file output:

A abc B abc
B abc C abc
C abc D abc
D abc ..
...

I tried this: sed 'N;s/\n/ /' but this removes the next line.

8 Answers

With sed:

sed '1{h;$p;d;};H;x;s/\n/ /;$G' file

On reading the first line; the line is stored into hold space (h). If it is also the last line (a file consisting of one line only) then it will be printed out ($p). Otherwise, it won't be printed. Then the pattern space is deleted and next cycle is started (d).

On each subsequent line: a newline character and the line just read is appended to the hold space (H), then hold and pattern spaces are exchanged (x). The newline character is replaced with a space (s/\n/ /). If it is the last line, the line just read will be appended to the current pattern space with a leading newline ($G).

Could you please try following, written based on shown samples. Written and tested it in https://ideone.com/6BGYTy

awk 'prev{print prev,$0} {prev=$0}' Input_file

OR in case you want to print last line then try:

awk 'prev{print prev,$0} {prev=$0} END{print}'  Input_file

Explanation: simply checking condition if prev is not null then print prev and current line. Then setting prev's value to current line. So in very first line it wouldn't print anything but from 2nd line onwards it will print lines as per OP's shown samples.

With paste, sed and bash (Process Substitution):

paste -d " " file <(sed 1d file)

Output:

A abc B abc
B abc C abc
C abc D abc
D abc ...
...

This might work for you (GNU sed):

sed 'N;s/\n\(.*\)/ \1&/;P;D' file

Append the next line and using pattern matching, insert that line (replacing the newline by a space) before the appended line.

The Pand D commands will print the first of the two lines and then delete it, leaving the second line intact, ready for the next line to be appended etc.

N.B. This will print an unpaired last line, to only print paired lines use:

sed 'N;s/\n\(.*\)/ \1&/;P;$d;D' file

An alternative unpaired/paired solution:

sed -Ez 's/\n(\S+)/ \1&/g' file

or:

sed -Ez 's/\n(\S+)/ \1&/g;s/[^\n]*\n$//' file

When the input is from a stream (not a file), you can change the solution of @Cyrus into

some_program | sed '2,$ s/.*/&\n&/' | paste -d" " - -

When some_program is running a long time, you will have to wait before seeing the results.

An improvement on Cyrus's answer, but with tail, (instead of sed), and plain sh:

tail -n +2 file | paste -d " " file -

If you want to modify the file itself, you can script ed:

ed -s input.txt <<'EOF'
1,$-1g/^/s/$/ /\
.+1t.\
.-1,.j
w
EOF

For each line but the last: add a space to the end, make a copy of the next line, and join the original line and that copy into a single line. Finally save the file.

In vi you can write a macro to do this.

  1. Open file in vi.

  2. Then type the following keystrokes

    ggqajYkpkJ0jq

Commentary

gg  # Go to Line 1 column 1
qa  # Begin recording macro a.
j   # Go to next line
Y   # Yank this line into buffer
k   # return to previous line
p   # Paste buffer below current line
k   # return to previous line
J   # Join line below cursor to current line
0   # Return to col 1 of current line
j   # go to next line
q   # Stop recording the macro

Your cursor should now be on Line 2 column 1.

You're now ready to execute your macro.

You've already completed line 1.

To run on remainder of file enter N-1@a where N=Number of lines in files.

If file has 100 lines enter 99@a to run macro on remaining 99 lines.

Related