Bash String Split by Delimiter Constrained by Number of Characters

I want to split a long text separated by spaces through bash, but I fail. The command below splits into characters, but not delimiters.

echo "The quick fox jumped over the lazy dog" | fold -w 10
echo "The quick fox jumped over the lazy dog" | sed -e 's/.\{9\}/&\n/g'

It would be nice to have it for some user bash interaction.

Input syntax

format_text 10 "The quick fox jumped over the lazy dog"

Output:

The quick 
fox jumped 
over the 
lazy dog

You must notice that the third line would cut "l" letter from "lazy" off if not for spacing spacing rule.

Update: The current result is good, There is some issue with the work slicer I cannot get by myself: it does not break words before the limit is transpassed.

#!/bin/bash

printHeader () {
    declare -i line_length=$3
    
    # Upper and lower fences 
    local upper_command="print \"$1\" *" 
    local upper_fence="$(python -c "$upper_command $line_length")"
    
    local lower_command="print \"$2\" *"
    local lower_fence="$(python -c "$lower_command $line_length")"
    
    # Slice words by some chracter counter
    local regex_counter="s/(.{$line_length}) /\1\n/g"
    
    # Complete line with dots and a pipe
    local res="$line_length - length"
    local repeat_pattern='$(repeat res \".\"; echo)'
    local fill_command="{res=($res); printf \"%s%s|\n\", $0, $repeat_pattern}"

    echo "$upper_fence"

    sed -r "$regex_counter" <<< $4

    echo "$lower_fence"
}

printHeader "#" "#" 10 "The quick fox jumped over the lazy dog"

Current output without final token:

##########
The quick fox
jumped over
the lazy dog
##########
5

1 Answer

sed -r 's/([^ .]+ [^ .]+) /\1\n/g' <<< "The quick fox jumped over the lazy dog"
The quick
fox jumped
over the
lazy dog

The character set [^ .]+ means one or more + characters of any kind . excluding the ^ whitespaces. So the capture group ([^ .]+ [^ .]+) matches for patterns as string string. The whole regular expression has an additional whitespace at the end ([^ .]+ [^ .]+) (it could be included in the capture group in order to preserve it).

With sed by using the substitute s command we replace the matched pattern by the content of the first capture group \1 and a new line character \n instead of the whitespace. By the flag g we repeat the command to the end of each line. The -r option activates the extended regular expressions.


Update - this is the actual answer:

sed -r 's/(.{8}) /\1\n/g' <<< "How do we know it is going to match the pre-defined number of characters?"
How do we
know it is
going to
match the
pre-defined
number of
characters?

In this example we capture strings with length at least 8 characters (including whitespaces) followed by a whitespace. We can check the actual length of the output lines in a way as this:

sed -r 's/(.{8}) /\1\n/g' <<< "How do we know it is going to match the pre-defined number of characters?" \
    | awk '{print length}'
9
10
8
9
11
9
11

And by the help of the answers of the question How to use printf to print a character multiple times? [awk] we can achieve the desired result.

sed -r 's/(.{8}) /\1\n/g' <<< "How do we know it is going to match the pre-defined number of characters?" \
    | awk '{rest=(12 - length); printf "%s%s|\n", $0, substr(".........", 1, rest)}'
How do we...|
know it is..|
going to....|
match the...|
pre-defined.|
number of...|
characters?.|

In case you want to break the words remove the final whitespace from the above regular expression /(.{8})/. Here is an example where the max line length will be exactly 10 characters or less, where the second sed command will trim the whitespaces around each new line.

sed -r 's/(.{10})/\1\n/g' <<< "How do we know it is going to match the pre-defined number of characters?" \
    | sed -r 's/(^ | $)//g' \
    | awk '{rest=(10 - length); printf "%s%s|\n", $0, substr(".........", 1, rest)}'
How do we.|
know it is|
going to..|
match the.|
pre-define|
d number o|
f characte|
rs?.......|
15

Your Answer

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

David Miller

David Miller

Executive Financial & Market Analyst

David Miller brings 15 years of experience in global economics, personal finance strategy, and market dynamics. He specializes in turning complex economic trends into actionable insights for everyday readers.

Share this article
Twitter Facebook Pinterest