Wrap text accounting for non-printing characters

colorscommand linetext formattingwrap

This question asks about wrapping text at a certain column, and people suggest using fold or fmt but as far as I can see, these simply count characters and don't allow for non-printing characters. For example:

fold -w 20 -s <<<`seq 1 25`

as one might expect, produces:

1 2 3 4 5 6 7 8 9 
10 11 12 13 14 15 
16 17 18 19 20 21 
22 23 24 25

but:

fold -w 20 -s <<<^[[32m`seq 1 25`^[[m

(where ^[ is the escape character) intuitively ought to produce the same thing in green text, but instead produces:

1 2 3 4 5 6 7 
8 9 10 11 12 13 14 
15 16 17 18 19 20 
21 22 23 24 25

in green text.

I can't see any switches that say to account for non-printing characters, and the PS1 approach to flagging non-printing characters doesn't seem to work with fold or fmt.

Is there something (ideally something standard) that can wrap text whilst accounting for non-printable characters?


EDIT:

The example above is really to simplify and demonstrate the problem but I may have over-simplified. To clarify my real-world example, I've got text where some words are in colour (using ANSI escape sequences) and I'd like that to wrap neatly. For example:

Here is some example text that contains ^[[31mred^[[m and ^[[32mgreen^[[m words that I would like to wrap neatly.

where ^[ is the escape character.

If I wanted this to wrap to 20 columns, I would expect:

Here is some
example text that
contains red and
green words that
I would like to
wrap neatly.

(with "red" and "green" in colour) but because of the ANSI escape codes, it wraps thus:

Here is some
example text
that contains
red and
green words
that I would like
to wrap neatly.

Best Answer

The ANSI escape sequence is being interpreted by the shell, not by the piping. So you're really inserting the text ^[[32m alongside with your sequence-output into you fold-command. If you want the whole text in green, you could try something like this:

echo -e "\e[32m"$(seq 1 25 | fold -w 20 -s)"\e[m"

or

echo -e "\e[32m"; seq -s ' '  1 25 | fold -w 20 -s; echo -e "\e[m"

Note that I'm using the \e as the escape character. This works directly within bash shells for testing.