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
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
rs
(reshape) command: rs -e 0 5 < file
Commented
Aug 3 at 0:40
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
raku -ne 'printf "%s%s", $_, $_%5 ?? " " !! "\n";'
Commented
Aug 5 at 6:29
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
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
.
Commented
Aug 3 at 11:22
Perl:
perl -0777ae 'while (@F) { print(join(" ", splice(@F, 0, 5)) . "\n") }' filename
0777
: read filename
at oncea
: 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
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
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
rs
?