3

I have the following file:

line 1
abc
line 2
def
line 3
ghi
.....
.....

I need it to become:

line 1 abc
line 2 def
line 3 ghi
......
......

I know how to remove newlines, but not odd or even line breaks.

7
  • 1
    This might help with GNU awk: awk 'NR%2{curr=$0; getline; print curr,$0}' file Commented Jul 6 at 13:06
  • 1
    Or awk 'NR%2 {getline n; print $0, n}' Commented Jul 6 at 16:08
  • 1
    The right answer will depend on how you want input that has an odd number of lines handled as there are various possible outputs given such input. Commented Jul 6 at 16:29
  • I'd be curious why answers to this question attracted so many downvotes. If the question's unclear to the point that it should not have been answered at all, I'd expect to see votes (down or close) on the question as well. Commented Jul 11 at 6:52
  • @Friedrich it's fairly common for someone to come along and decide to downvote all answers to a question that they think didn't deserve to be answered. Common enough that there are questions on SE Meta about the behavior, e.g. is-it-okay-to-downvote-answers-to-bad-questions. I expect in this case it was because the OP didn't show any code in their question. Oh well... Commented Jul 13 at 13:06

7 Answers 7

4

This might work for you (GNU sed):

sed -i 'N;s/\n/ /' file

Append the following line and replace the newline with a space.

Alternative using paste:

paste -sd' \n' file
Sign up to request clarification or add additional context in comments.

3 Comments

Works in BSD sed too.
@potong trying to understand: sed read the first line in the file and put it in the "pattern space"; then the 'N' option tells sed to read the second line and put it too in the "pattern space"; then there is the simple substitution from '\n' newline to 'space' of what is in the "pattern space". Is it correct ?
Yes. When sed automatically populates the pattern space it removes the newline and re-appends it when the sed cycle ends (unless it is deleted completely i.e. d or D commands). The N command causes the newline to be re-appended and the next line (if it exists) to appended minus its newline. Then the substitution command s replaces the newline with a space.
3

In Vim, there are several ways to do this without having to leave the comfort of your favorite text editor.

Using :global

Match every line and join with the next line. The command :g/./ matches any non-blank line, i.e. it will yield correct results even if there are several paragraphs that need to be joined. It can be prefixed with a range of lines to operate on (default: whole buffer). It is followed by the :join command to join the following line. As :global "walks" through the buffer from top to bottom, it will skip the just-joined line.

:[range]g/./j

See :help :global and :help :join.

Using a (recursive) macro

You can record the command to join lines (J) and then proceed to the next line (j). These two commands can be recorded into a register (e.g. a) and replayed as explained in :help complex-repeat:

qaJjq

Replay twice with 2@a.

To operate on all lines of the buffer, record a recursive macro like this:

qaqqaJj@aq

And replay with @a.

Explanation:
qaq records an empty macro, effectively clearing register a so nothing happens when we call it during recording.
qaJj starts recording and does the join-advance steps.
@a is the recursive macro call to the (still empty) register a.
q finishes recording and a is now ready to be run.

Filter through an external command

This is cheating a little bit as we let Vim filter the current buffer through an external command. This means we can easily leverage any of the other solutions (as long as we remember to escape any special character).

Using the first solution from Ed Morton's answer, we would run:

:%!awk 'NR\%2{p=$0; next} {print p, $0}'

Note that the % needed to be escaped. The reference documentation is found in :help :range!.

Comments

2

I would harness GNU AWK for this task following way, let file.txt content be

line 1
abc
line 2
def
line 3
ghi
.....
.....

then

awk '{printf("%s%s",$0,NR%2?" ":"\n")}' file.txt

gives output

line 1 abc
line 2 def
line 3 ghi
..... .....

Explanation: I use printf and so-called ternary operator. First part is always whole line ($0) second part is space if remainder of division of number of line is non-zero (i.e. line is odd) and newline otherwise.

(tested in GNU Awk 5.3.1)

Comments

2

Using any awk:

  1. Do not print the last input line if odd number of input lines:
    <PS1> awk 'NR%2{p=$0; next} {print p, $0}' file
    line 1 abc
    line 2 def
    line 3 ghi
    ..... .....
    <PS1> 
  1. Print the last input line without a terminating newline (so not a valid POSIX test file) if odd number of input lines:
    <PS1> awk 'NR%2{printf "%s", $0; next} {print OFS $0}'
    line 1 abc
    line 2 def
    line 3 ghi
    ..... .....
    <PS1> 
  1. Print the last input line followed by a newline if odd number of input lines:
    <PS1> awk 'NR%2{p=$0; next} {print p, $0} END{if (NR%2) print p}' file
    line 1 abc
    line 2 def
    line 3 ghi
    ..... .....
    <PS1> 

There are other possibilities too but the right answer all depends on how you want input that has an odd number of lines handled because while they all produce the same output given the sunny-day case of an even number of input lines, as shown above, they'll each do different things given the rainy-day case of an odd number of input lines:

  1. Do not print the last input line if odd number of input lines:
    <PS1> seq 5 | awk 'NR%2{p=$0; next} {print p, $0}' | cat -e
    1 2$
    3 4$
    <PS1>
  1. Print the last input line without a terminating newline (so not a valid POSIX test file) if odd number of input lines:
    <PS1> seq 5 | awk 'NR%2{printf "%s", $0; next} {print OFS $0}' | cat -e
    1 2$
    3 4$
    5<PS1>
  1. Print the last input line followed by a newline if odd number of input lines:
    <PS1> seq 5 | awk 'NR%2{p=$0; next} {print p, $0} END{if (NR%2) print p}' | cat -e
    1 2$
    3 4$
    5$
    <PS1>

To learn awk, get the book Effective AWK Programming, 5th Edition, by Arnold Robbins.

Comments

0

Don't waste time doing modulos when none are required. Just keep inverting a boolean flag :

echo 'line 1
abc
line 2
def
line 3
ghi' | 

awk 'ORS = (_ = !_) ? FS : RS'

line 1 abc
line 2 def
line 3 ghi

9 Comments

Can downvoters explain? It seems a valid solution to me...
See my comment below. Apparently the new comments don't allow to @-mention anybody in a reply... Oh, and there are two downvotes on the question and nearly all answers, btw.
it's beyond baffling to me. Because unlike the sed solutions, mine doesn't even need to temporarily store the current row; unlike other awk solutions, mine doesn't require performing modulo-ops; and unlike other vim solutions, mine doesn't require generating cryptic macro sequences like qaqqaJj@aq
There was a very thorough discussion of the drawbacks by @EdMorton which was deleted, unfortunately. Maybe Ed can be persuaded to point out the weaknesses of this answer once more?
@RAREKpopManifesto, honestly, if I wanted to be pedantic, I would have criticized the usage of Underscore instead of a proper name and asked for some explainations. But for the rest, I find it pretty elegant.
@Setop : well if you're allergic to that underscore variable then use this version instead ::::::::::::::: :::::::::::::: awk 'ORS = ORS < FS ? FS : RS'
what proper name would you use instead for a continuously inverting boolean flag ?
maybe is_odd would be meaningful
because writing it as ORS = (is_odd = ! is_odd) ? … : … is all that clear to the reader ? :::::::::: :::::::: is_odd <— not is_odd sounds very clunky to me.
0

Use this Perl one-liner:

perl -lne 'if ( $. % 2 ) { $prev = $_; print if eof; } else { print "$prev $_"; }' infile

Examples:

Even number of input lines:

seq 1 10 | perl -lne 'if ( $. % 2 ) { $prev = $_; print if eof; } else { print "$prev $_"; } '

Output:

1 2
3 4
5 6
7 8
9 10

Odd number of input lines:

seq 1 9 | perl -lne 'if ( $. % 2 ) { $prev = $_; print if eof; } else { print "$prev $_"; }'

Output:

1 2
3 4
5 6
7 8
9

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-n : Loop over the input one line at a time, assigning it to $_ by default.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing.

$. : Current input line number.
eof : End of file. A test for this (and the subsequent print) is needed for printing the last line if the input in case the number of lines is odd.

See also:

Comments

-2

You can use Raku/Sparrow for that. Given input data in data.txt file:

task.bash

cat data.txt

task.check

:any:

code: <<OK
!raku
"data.out".IO.spurt(
  captures-full().flat.map({
    $_<index> %2 == 0 ??
    $_<data> ~ " "    !! $_<data> ~ "\n"
  }).join("")
);
OK

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.