Splitting long lines in bash with numbering

Viewed 60

I'm trying to write script that partition very long text (one line) to multiple lines. The requirement is that every line must have prefixes with numbering. I tried using sed but I have problem with numbering matches. My code:

 sed -e "s/.\{4\}/part = &\\
 /g"

Input:

AAAAAAAAABBBBBBBAAAAAAABBBBBBB

Output:

part = AAAA
part = AAAA
part = ABBB
part = BBBB
part = AAAA
part = AAAB
part = BBBB
BB

Expected:

part1 = AAAA
part2 = AAAA
part3 = ABBB
part4 = BBBB
part5 = AAAA
part6 = AAAB
part7 = BBBB
part8 = BB

Additional problem is the last part that is not labeled. Is it possible to do it with sed? Or maybe any other shell tools?

6 Answers

With GNU awk:

awk '{for(i=1; i<=NF; i++){print "part" i,"=",$i}}' FPAT='.{1,4}' file

Output:

part1 = AAAA
part2 = AAAA
part3 = ABBB
part4 = BBBB
part5 = AAAA
part6 = AAAB
part7 = BBBB
part8 = BB

From man awk:

FPAT: A regular expression describing the contents of the fields in a record. When set, gawk parses the input into fields, where the fields match the regular expression, instead of using the value of FS as the field separator.

The "hard" part of that, actually splitting the input into lines, is the job that fold exists to do:

$ echo 'AAAAAAAAABBBBBBBAAAAAAABBBBBBB' |
    fold -w 4 | awk '{print "part" NR " = " $0}'
part1 = AAAA
part2 = AAAA
part3 = ABBB
part4 = BBBB
part5 = AAAA
part6 = AAAB
part7 = BBBB
part8 = BB

Using fold will make your life easier if/when your requirements change to, say, try to only split at blanks.

Here is a simpler gnu awk solution:

s='AAAAAAAAABBBBBBBAAAAAAABBBBBBB'
awk -v RS='[^\n]{1,4}' 'RT{print "part" NR, "=", RT}' <<< "$s"
part1 = AAAA
part2 = AAAA
part3 = ABBB
part4 = BBBB
part5 = AAAA
part6 = AAAB
part7 = BBBB
part8 = BB 

With GNU tools:

echo "$str" | grep -oE '.{,4}' | nl -s ' = ' | sed -E 's/^ +/part/'
part1 = AAAA
part2 = AAAA
part3 = ABBB
part4 = BBBB
part5 = AAAA
part6 = AAAB
part7 = BBBB
part8 = BB

Another GNU awk, using builtin variable RT:

$ echo AAAAAAAAABBBBBBBAAAAAAABBBBBBB | 
awk -v RS=".{1,4}" '{printf "%spart%d = %s",(++i>1?ORS:""),i,RT}'

Sample output:

part1 = AAAA
part2 = AAAA
...
part8 = BB

In your code, the = in the replacement string of s command is just a literal = character, not a line number. This problem could be solved in pure sed using 3 sed commands in a pipeline like that:

line='AAAAAAAAABBBBBBBAAAAAAABBBBBBB'

echo "$line"                  |
sed 's/.\{4\}/&\n/g; s/\n$//' |
sed =                         |
sed 'N; s/\(.*\)\n\(.*\)/part\1 = \2/'

which outputs

part1 = AAAA
part2 = AAAA
part3 = ABBB
part4 = BBBB
part5 = AAAA
part6 = AAAB
part7 = BBBB
part8 = BB
Related