7

I have a file that contains a long column and I want to split it into lines, each one with 5 values.

E.g., Input file:

1
2
3
4
5
6
7
8
9
10

Output file:

1 2 3 4 5
6 7 8 9 10
1
  • 2
    Can you explain why you need to do this in AWK? As opposed to using a tool designed for the job, such as rs? Commented Aug 4 at 8:35

6 Answers 6

21

Using paste:

paste -d' ' - - - - - < /path/to/file

-d' ' specifies space as the output delimiter
- - - - - specifies that the input will be read 5 times, combining 5 lines into one.


Using awk:

awk '{printf "%s ", $0; if (NR % 5 == 0) printf "\n"}' /path/to/file

This will print each line followed by a space and print a newline every 5 lines.


Using sed:

sed 'N;N;N;N;s/\n/ /g'

N appends the next line to the pattern space (done four times to append four additional lines, making it five lines total in the pattern space).
s/\n/ /g replaces all newline characters with a space in the pattern space.


Using ed:

,s/$/ /
g//.,+4j
wq

,s/$/ / will add a space to the end of every line.
g//.,+4j will join all lines in groups of 5 (the empty regular expression reuses the $ expression from the s command).


Using pr:

pr -at -5 -s' '

-a: print columns across
-t: omit header
-5: 5 columns
-s' ': separate with space

1
  • 4
    Nice roundup! there's also the venerable rs (reshape) command: rs -e 0 5 < file Commented Aug 3 at 0:40
10

Using any awk:

$ seq 10 | awk '{ printf "%s%s", $0, (NR%5 ? OFS : ORS) }'
1 2 3 4 5
6 7 8 9 10

or if you prefer:

$ seq 10 | awk -v ORS= '{ print $0 (NR%5 ? OFS : RS) }'
1 2 3 4 5
6 7 8 9 10
3
8

If you must use awk, then one option is to set the output record separator ORS conditional on whether the record number NR is divisible by 5:

awk '{ORS = NR % 5 ? " " : "\n"} 1'

Ex.

$ seq 1 10 | awk '{ORS = NR % 5 ? " " : "\n"} 1'
1 2 3 4 5
6 7 8 9 10
5
  • please can you explain your command line // awk '{ORS = NR % 5 ? " " : "\n"} 1' . thank you Commented Aug 3 at 3:18
  • 1
    Consider using awk builtin variables such as OFS and RS instead of hard-coding " " and "\n" so the output and record separators can be changed just by modifying the usual variables and the output record separator will automatically be whatever the RS/ORS is set to by default on the system it's running on, e.g. \n or \r\n.
    – Ed Morton
    Commented Aug 3 at 11:22
  • 2
    @EdMorton I considered that but unfortunately second guessed myself Commented Aug 3 at 12:22
  • 1
    @DjabriJosef please consider accepting this answer instead Commented Aug 3 at 12:22
  • 1
    This answer is fine, no reason to accept mine instead, I was just providing some alternatives for consideration. I would still recommend using OFS and RS in it though.
    – Ed Morton
    Commented Aug 3 at 12:24
4

Perl:

perl -0777ae 'while (@F) { print(join(" ", splice(@F, 0, 5)) . "\n") }' filename
  • 0777: read filename at once
  • a: autosplit the contents of filename into @F
  • while (@F) { [...] }: as long as there are more than 0 elements in @F, attempt to remove 5 elements (or less if less than 5 elements are left) and join them using space as a separator, then print them followed by a newline character
% seq 1 10 | perl -0777ae 'while (@F) { print(join(" ", splice(@F, 0, 5)) . "\n") }'
1 2 3 4 5
6 7 8 9 10
3

Using Raku (formerly known as Perl_6)

For complete 'sets' of 5 lines (incomplete 'sets' at end are dropped):

~$ raku -e '.put for lines.rotor(5);'  file

OR:

Group into 'sets' of 5 lines, saving partial 'sets' at end:

~$ raku -e '.put for lines.rotor(5, :partial);'  file

#OR:

~$ raku -e '.put for lines.batch(5);'  file

Above are answers coded in Raku, a member of the Perl-family of programming languages. Among other things, Raku features high-level support for Unicode and 'rational' mathematics, built-in.

Above shows off Raku's rotor/batch routines, which can group together elements for you. If you want to drop incomplete sets of elements, use rotor without any extra parameters. If you want to preserve incomplete sets at the end of a file, use rotor with the partial => True parameter (abbreviated :partial). Or just use batch.

Sample Input:

1
2
3
4
5
6
7
8
9
10
11

Sample Output 1 (rotor default):

1 2 3 4 5
6 7 8 9 10

Sample Output 2 (batch default, or rotor with partial => True or simply :partial):

1 2 3 4 5
6 7 8 9 10
11

https://blogs.perl.org/users/zoffix_znet/2016/01/perl-6-rotor-the-king-of-list-manipulation.html
https://docs.raku.org/routine/rotor
https://docs.raku.org/routine/batch
https://raku.org

2

Another (kind of silly) awk solution, using a counter a:

$ awk ' { line=line " " $0 ; if (++a == 5) { a=0 ; print substr(line,2) ; line="" } }' \
  input.txt
1 2 3 4 5
6 7 8 9 10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .