4

The file looks like this (one big line):

a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a; etc......

Now I want to cut the text and do a line break after every fifth semicolon (;) so it looks like this:

a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
etc....

How do I do this?

4 Answers 4

18

With tr and paste

tr ';' '\n' < semicolons | paste -d';' - - - - -

Tests

$ cat semicolons
a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a

$ tr ';' '\n' < semicolons | paste -d';'  - - - - -
a;a;a;a;a
a;a;a;a;a
a;a;a;a;a
a;a;a;a;a
a;a;a;a;a
a;a;a;a;a
a;a;a;a;a
a;a;a;a;a
a;a;a;a;a

Both tr and paste are specified in POSIX standard.

To add the required semicolon ; at the end of the lines

tr ';' '\n' < semicolons | paste -d';' - - - - - | sed s/$/\;/

Tests

$ tr ';' '\n' < semicolons | paste -d';' - - - - - | sed s/$/\;/
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;    
2
  • 5
    good one. Alternately tr ';' '\n' < semicolons | paste -sd';;;;\n'
    – iruvar
    Mar 5, 2020 at 15:34
  • @iruvar Good catch ;) Mar 5, 2020 at 15:41
13

Purely using GNU sed substitution:

sed 's/\(\([^;]*;\)\{5\}\)/\1\n/g'

or without all the escaping backslashes using -E (thanks @JoL):

sed -E 's/(([^;]*;){5})/\1\n/g'

Example:

$ cat test.txt
a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a;a; etc......

$ cat test.txt | sed 's/\(\([^;]*;\)\{5\}\)/\1\n/g'
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a;a;
a;a;a;a; etc......

Explanation:

  • \([^;]*;\): regex capture group matching all characters up to and including a semi-colon.
  • \(\([^;]*;\)\{5\}\): regex capture group matching five occurrences of the above. In the sed command, this will be matched into \1.
  • s/\(\([^;]*;\)\{5\}\)/\1\n/g: substitute (s/) every occurrence (/g) of the group of five occurrences of all characters up to and including a semicolon (\(\([^;]*;\)\{5\}\)) with itself (\1), but followed by a newline character (\n).
2
  • Also Thanks!!! Solved!
    – Coreta
    Mar 5, 2020 at 15:39
  • 3
    You can skip the backslashes in the pattern by using -r (GNU option) or -E (GNU and POSIX option). I.e. sed -E 's/(([^;]*;){5})/\1\n/g'
    – JoL
    Mar 6, 2020 at 0:49
5

Sed editor method we place a newline after the 5th semicolon, print upto the newline, remove upto newline, rinse n repeat till you run out of the pattern space.

$ sed -e 's/;/;\n/5;P;D' file 

With Perl, use semicolon as field separator and print in bunches of 5 with semicolons as OFS and an empty field at the end to get the trailing semicolon printed :

$ perl -F\; -lane '$,=";";
     print splice(@F, 0, 5), q() while @F;
' file 

Using Awk we look at a bunch of 5 fields and append a semicolon to the first 4 and semicolon + newline to the fifth. Then print the fields with a null separating them:

$ awk -F\; -vOFS= '{
        for(i=1; i<=NF; i++)
            $(i) = $(i) (i%5 ? FS : FS RS)
  }1' file
1
  • Upvoted for impressive Sed and Perl solutions (the Awk solution prints an extraneous semi-colon at the very end). Mar 7, 2020 at 20:33
0

I find that while regexes are appropriate for this kind of task, I always do it with text editor macros for the visual help and simplicity.

Using vim, you can

set textwidth=20

or similarly low and

set wrap

and if the file really needs editing, a simple macro like

qqf;f;f;f;f;i\n99999@q

would do it.

You must log in to answer this question.

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