23

How would I join two lines using awk or sed?

I have data that looks like this:

abcd
joinabcd
efgh
joinefgh
ijkl
joinijkl

I need an output like the one below:

joinabcdabcd
joinefghefgh
joinijklijkl
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Vijay
  • 65,327
  • 90
  • 227
  • 319

7 Answers7

53
awk '!(NR%2){print$0p}{p=$0}' infile
Dimitre Radoulov
  • 27,252
  • 4
  • 40
  • 48
  • 9
    Would anybody care to explain how this awk expression works? Mostly the !(NR%2) part. – mjuarez Jul 23 '16 at 03:53
  • 13
    NR represents the number of rows... % is the modulu operator (i.e. a%b is the remainder when a is divided by b)... (NR%2) is the modulu of NR by two, i.e. is true when NR is even and false when odd... !(NR%2) is true when NR is odd, thus... !(NR%2){print$0p} means the program will print the line concatenated with the variable p, only on odd lines... {p=$0} means that on every line, p is set to be the current line (but only after printing the current and previous line if the current line is odd). – shiri Aug 25 '16 at 14:26
  • 1
    With an odd number of input lines, this method will not print the final line. – Bryon Nicoson Jan 30 '18 at 18:28
  • 3
    @BryonNicoson, correct, even though the OP sample seemed to have even number of lines. This would handle odd number of lines: `awk 'END{if((NR%2))print p}!(NR%2){print$0p}{p=$0}'` – Dimitre Radoulov Jan 30 '18 at 22:53
10

You can use printf with a ternary:

    awk '{printf (NR%2==0) ? $0 "\n" : $0}'
Bryon Nicoson
  • 903
  • 11
  • 11
  • 2
    This answer doesn't give the correct result. For example, the OP requires *joinabcdabcd* for the first line but this one-liner outputs *abcdjoinabcd*. But if alternating consecutive concatenation is what you want, then the easiest solution is `lam - - – Clint Pachl Sep 08 '20 at 01:14
  • 1
    This doesn't work if the input file contains format specifiers, such as `%s`. – viluon Jan 18 '21 at 18:43
5
awk 'BEGIN{i=1}{line[i++]=$0}END{j=1; while (j<i) {print line[j+1] line[j]; j+=2}}' yourfile

No need for sed.

Vijay
  • 65,327
  • 90
  • 227
  • 319
bashflyng
  • 911
  • 1
  • 6
  • 5
  • 1
    Good answer....but i suppose i asked for complete line not just the first field.so now it need to be changed as `line[i++]=$0` instead of `line[i++]=$1`.But a very good answer thanks:) – Vijay Jul 07 '10 at 12:42
3

Here it is in sed:

sed 'h;s/.*//;N;G;s/\n//g' < filename
Beta
  • 96,650
  • 16
  • 149
  • 150
3

They say imitation is the sincerest form of flattery.
Here's a Perl solution inspired by Dimitre's awk code:

perl -lne 'print "$_$p" if $. % 2 == 0; $p = $_' infile

$_ is the current line
$. is the line number

Chris Koknat
  • 3,305
  • 2
  • 29
  • 30
1

Some improvement to the "sed" script above that will take the following: 1008
-2734406.132904 2846
-2734414.838455 4636
-2734413.594009 6456
-2734417.316269 8276
-2734414.779617

  and make it :    

1008 -2734406.132904
2846 -2734414.838455
4636 -2734413.594009
6456 -2734417.316269
8276 -2734414.779617

  the "sed" is : "sed 'h;s/.*//;G;N;s/\n/ /g'"
0

This is the answer to the question "How to make the count and the file appear on the same line" in the command:

find . -type f -exec fgrep -ci "MySQL" {} \; -print

Bryon Nicolson's answer produced the best result.

ian
  • 12,003
  • 9
  • 51
  • 107
Mark
  • 116
  • 4