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...
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
##########
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?.......|