4

At the Linux/Unix command line, I want to turn this:

A
B
C
A
B
C
.
.
.

into this:

A,B,C
A,B,C
...

Is there a simple built-in command to do this, or does this require diving into Awk, Perl, etc.?

7

Don't know such built-in. Using Bash you can:

while read a && read b && read c ; do echo $a,$b,$c ; done < file
  • 1
    If you have only 5 lines, you may not want to lose lines 4 and 5 just because you don't have line 6. – musiphil Oct 16 '14 at 17:19
4

That is horrible, surely something like

tr \\n ' '

would do the same thing?

So for e.g. to join lines of the file file_lines use

cat file_lines | tr \\n ' '
  • 6
    He didn't want all of it on a single line, it seems. – l0b0 Feb 17 '12 at 10:42
  • Exactly. Referencing the problem statement, this would produce a single line with everything on it (A B C A B C A B C A B C A B C ...) which is not what was requested. – Alan Krueger Feb 17 '12 at 17:08
2

If you're lucky enough to have no spaces in the input, then

xargs -n3 echo |tr ' ' ,

would do it.

  • That's a good one that I was going to suggest. Very elegant. If you do have spaces, use xargs -l3 – xpt Aug 20 '15 at 0:49
  • The tr will mangle the output if there are spaces in the input, even with xargs -l – Steven Taschuk Aug 20 '15 at 1:16
  • Alright then, I'll provide my own answer. – xpt Aug 20 '15 at 1:18
2

POSIX solution with pr:

pr -3 -a -t -s, file

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pr.html

0

Here is a solution in python:

#!/usr/bin/python3

def njoin(filename, outfn="", n=3, linesuffix=" "):
    if not outfn:
        outfn = filename + ".join"
    with open(filename) as infh, open(outfn, "w") as outfh:
        nline = 0
        for line in infh:
            if nline % n != n-1:
                line = line.rstrip() + linesuffix
            outfh.write(line)
            nline += 1

In your case you can use the function like this:

njoin("/path/to/file", n=3, linesuffixe=",")
0

The sample you gave have 3 lines but your topic emphasize on N lines of input, so I would assume that 3 lines is only for illustration purpose, and what you really need is that N lines of input, which could be as much as over 10, which in turn making that accepted bash script unmanageable.

There are simple built-in commands to do this, without diving into Awk, or Perl. Here is one way.

First, the sample input,

 $ seq 12 | cat -n 
     1  1
     2  2
     3  3
     4  4
     5  5
     6  6
     7  7
     8  8
     9  9
    10  10
    11  11
    12  12

Now suppose N=4:

N=4
$ seq 12 | cat -n | sed 's/$/,/' | xargs -l$N | sed 's/,$//'
1 1, 2 2, 3 3, 4 4
5 5, 6 6, 7 7, 8 8
9 9, 10 10, 11 11, 12 12

I believe that should be close to what you are looking for.

0

GNU/Linux command to merge every group of N lines into one line is a paste command. This is not a built-in command, but it is part of the coreutils, so it is installed by default.

Your example will look as follows:

user@host:~$ cat ABC.text
A
B
C
A
B
C

user@host:~$ cat ABC.text | paste - - - -d,
A,B,C
A,B,C

If there is just 5 input lines, then last output line will be incomplete:

user@host:~$ cat ABC.text | head -5 | paste - - - -d,
A,B,C
A,B,

If we want to group lines not by 3, but by 2:

user@host:~$ cat ABC.text | paste - - -d,
A,B
C,A
B,C

If there is just 5 input lines, then last output line will be incomplete:

user@host:~$ cat ABC.text | head -5 | paste - - -d,
A,B
C,A
B,

As you can see, you are putting as many - (which in this case refers to stdin), as number of lines you want to merge into one. If the number of input lines is insufficient, the last joint line will be incomplete.

To handle a larger number of lines in a group, you just have to add more -.

See man paste for additional information.


Let's look at a real example: output of iwlist command. First, let's choose only ESSID lines from the output (and let's add a bit of obfuscation; this part will not change, so it can be ignored):

user@host:~$ iwlist wifi scanning | grep "ESSID" | sed -e 's/^ *//g' -e 's/\(ess: ...\)\(.*\)\(...$\)/\1XX:XX:XX:XX\3/g' -e "s/\(ESSID:\"\)\(.....\)\(.*\"\)/\1\2......\"/g" 
ESSID:"DIREC......"
ESSID:"MGTS_......"
ESSID:"the g......"
ESSID:"MGTS_......"
ESSID:"sunny......"
ESSID:"beeli......"
ESSID:"Beeli......"
ESSID:"HG530......"
ESSID:"MGTS_......"
ESSID:"Home_......"

If later we want to add addresses to our output, then the output will turn into alternating lines with addresses and ESSID.

user@host:~$ iwlist wifi scanning | grep "Cell\|ESSID" | sed -e 's/^ *//g' -e 's/\(ess: ...\)\(.*\)\(...$\)/\1XX:XX:XX:XX\3/g' -e "s/\(ESSID:\"\)\(.....\)\(.*\"\)/\1\2......\"/g"
Cell 01 - Address: 12:XX:XX:XX:XX:7A
ESSID:"DIREC......"
Cell 02 - Address: 70:XX:XX:XX:XX:32
ESSID:"MGTS_......"
Cell 03 - Address: E0:XX:XX:XX:XX:73
ESSID:"the g......"
Cell 04 - Address: 44:XX:XX:XX:XX:D2
ESSID:"MGTS_......"
Cell 05 - Address: 00:XX:XX:XX:XX:54
ESSID:"sunny......"
Cell 06 - Address: 00:XX:XX:XX:XX:7C
ESSID:"beeli......"
Cell 07 - Address: EC:XX:XX:XX:XX:DC
ESSID:"Beeli......"
Cell 08 - Address: C8:XX:XX:XX:XX:9F
ESSID:"HG530......"
Cell 09 - Address: CC:XX:XX:XX:XX:02
ESSID:"MGTS_......"
Cell 10 - Address: 28:XX:XX:XX:XX:E8
ESSID:"Home_......"

To merge every two lines into one, add | paste - -:

user@host:~$ iwlist wifi scanning | grep "Cell\|ESSID" | sed -e 's/^ *//g' -e 's/\(ess: ...\)\(.*\)\(...$\)/\1XX:XX:XX:XX\3/g' -e "s/\(ESSID:\"\)\(.....\)\(.*\"\)/\1\2......\"/g" | paste - -
Cell 01 - Address: 12:XX:XX:XX:XX:7A    ESSID:"DIREC......"
Cell 02 - Address: 70:XX:XX:XX:XX:32    ESSID:"MGTS_......"
Cell 03 - Address: E0:XX:XX:XX:XX:73    ESSID:"the g......"
Cell 04 - Address: 44:XX:XX:XX:XX:D2    ESSID:"MGTS_......"
Cell 05 - Address: 00:XX:XX:XX:XX:54    ESSID:"sunny......"
Cell 06 - Address: 00:XX:XX:XX:XX:7C    ESSID:"beeli......"
Cell 07 - Address: EC:XX:XX:XX:XX:DC    ESSID:"Beeli......"
Cell 08 - Address: C8:XX:XX:XX:XX:9F    ESSID:"HG530......"
Cell 09 - Address: CC:XX:XX:XX:XX:02    ESSID:"MGTS_......"
Cell 10 - Address: 28:XX:XX:XX:XX:E8    ESSID:"Home_......"

If later we want to add a Protocol, Bit rates and Frequency, then the output will be a list of groups of 5 lines eash (address, ESSID, Protocol, Frequency, and Bit Rates).

user@host:~$ iwlist wifi scanning | grep "Cell\|ESSID\|Protocol\|Rates\|Frequency" | sed -e 's/^ *//g' -e 's/\(ess: ...\)\(.*\)\(...$\)/\1XX:XX:XX:XX\3/g' -e "s/\(ESSID:\"\)\(.....\)\(.*\"\)/\1\2......\"/g"
Cell 01 - Address: 12:XX:XX:XX:XX:7A
ESSID:"DIREC......"
Protocol:IEEE 802.11gn
Frequency:2.412 GHz (Channel 1)
Bit Rates:144 Mb/s
Cell 02 - Address: 70:XX:XX:XX:XX:32
ESSID:"MGTS_......"
Protocol:IEEE 802.11bgn
Frequency:2.412 GHz (Channel 1)
Bit Rates:130 Mb/s
Cell 03 - Address: E0:XX:XX:XX:XX:73
ESSID:"the g......"
Protocol:IEEE 802.11bg
Frequency:2.412 GHz (Channel 1)
Bit Rates:54 Mb/s
Cell 04 - Address: 44:XX:XX:XX:XX:D2
ESSID:"MGTS_......"
Protocol:IEEE 802.11bgn
Frequency:2.412 GHz (Channel 1)
Bit Rates:130 Mb/s
Cell 05 - Address: 00:XX:XX:XX:XX:54
ESSID:"sunny......"
Protocol:IEEE 802.11bg
Frequency:2.427 GHz (Channel 4)
Bit Rates:54 Mb/s
Cell 06 - Address: 00:XX:XX:XX:XX:7C
ESSID:"beeli......"
Protocol:IEEE 802.11bgn
Frequency:2.422 GHz (Channel 3)
Bit Rates:300 Mb/s
Cell 07 - Address: EC:XX:XX:XX:XX:DC
ESSID:"Beeli......"
Protocol:IEEE 802.11bgn
Frequency:2.437 GHz (Channel 6)
Bit Rates:108 Mb/s
Cell 08 - Address: C8:XX:XX:XX:XX:9F
ESSID:"HG530......"
Protocol:IEEE 802.11bgn
Frequency:2.447 GHz (Channel 8)
Bit Rates:108 Mb/s
Cell 09 - Address: CC:XX:XX:XX:XX:02
ESSID:"MGTS_......"
Protocol:IEEE 802.11bgn
Frequency:2.442 GHz (Channel 7)
Bit Rates:130 Mb/s
Cell 10 - Address: 28:XX:XX:XX:XX:E8
ESSID:"Home_......"
Protocol:IEEE 802.11bgn
Frequency:2.472 GHz (Channel 13)
Bit Rates:108 Mb/s

To merge every 5 lines into one, just add | paste - - - - -.

user@host:~$ iwlist wifi scanning | grep "Cell\|ESSID\|Protocol\|Rates\|Frequency" | sed -e 's/^ *//g' -e 's/\(ess: ...\)\(.*\)\(...$\)/\1XX:XX:XX:XX\3/g' -e "s/\(ESSID:\"\)\(.....\)\(.*\"\)/\1\2......\"/g" | paste - - - - - 
Cell 01 - Address: 12:XX:XX:XX:XX:7A    ESSID:"DIREC......" Protocol:IEEE 802.11gn  Frequency:2.412 GHz (Channel 1) Bit Rates:144 Mb/s
Cell 02 - Address: 70:XX:XX:XX:XX:32    ESSID:"MGTS_......" Protocol:IEEE 802.11bgn Frequency:2.412 GHz (Channel 1) Bit Rates:130 Mb/s
Cell 03 - Address: E0:XX:XX:XX:XX:73    ESSID:"the g......" Protocol:IEEE 802.11bg  Frequency:2.412 GHz (Channel 1) Bit Rates:54 Mb/s
Cell 04 - Address: 44:XX:XX:XX:XX:D2    ESSID:"MGTS_......" Protocol:IEEE 802.11bgn Frequency:2.412 GHz (Channel 1) Bit Rates:130 Mb/s
Cell 05 - Address: 00:XX:XX:XX:XX:54    ESSID:"sunny......" Protocol:IEEE 802.11bg  Frequency:2.427 GHz (Channel 4) Bit Rates:54 Mb/s
Cell 06 - Address: 00:XX:XX:XX:XX:7C    ESSID:"beeli......" Protocol:IEEE 802.11bgn Frequency:2.422 GHz (Channel 3) Bit Rates:300 Mb/s
Cell 07 - Address: EC:XX:XX:XX:XX:DC    ESSID:"Beeli......" Protocol:IEEE 802.11bgn Frequency:2.437 GHz (Channel 6) Bit Rates:108 Mb/s
Cell 08 - Address: C8:XX:XX:XX:XX:9F    ESSID:"HG530......" Protocol:IEEE 802.11bgn Frequency:2.447 GHz (Channel 8) Bit Rates:108 Mb/s
Cell 09 - Address: CC:XX:XX:XX:XX:02    ESSID:"MGTS_......" Protocol:IEEE 802.11bgn Frequency:2.442 GHz (Channel 7) Bit Rates:130 Mb/s
Cell 10 - Address: 28:XX:XX:XX:XX:E8    ESSID:"Home_......" Protocol:IEEE 802.11bgn Frequency:2.472 GHz (Channel 13)    Bit Rates:108 Mb/s

EOT

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.