Reputation: 46795
The bash manual says that, in the prompt, any sequences of non-printing characters should be enclosed like: \[this\]
:
\[ Begin a sequence of non-printing characters.
This could be used to embed a terminal control sequence into the prompt.
\] End a sequence of non-printing characters.
Given a string to be included in the prompt, how can i automatically escape all ANSI control / color codes, to make the prompt display / wrap correctly under all circumstances?
Differentiation: Here i assume that a string with ANSI control codes has already been produced.
This related question assumes that the delimiters can be inserted by editing the string's generating function.
Upvotes: 0
Views: 524
Reputation: 123470
Don't try to automate it.
The reason why Bash asks you to add the \[...\]
's manually is because the shell can't reasonably know how any given terminal will interpret any escape codes. If it was, Bash would just do it in the first place.
For example, here are a few of the many cases that the other answer fails to handle. In each case, no output is printed on my particular terminal and yet the escaping function fails to escape them:
printf '\e]1;Hello\a' # Set window title
printf '\e[0;2;0;0;0}' # 24-bit color
printf '\e[13]' # Unblank screen
Upvotes: 0
Reputation: 46795
The following will enclose ANSI control sequences in ASCII SOH
(^A
) and STX
(^B
) which are equivalent to \[
and \]
respectively:
function readline_ANSI_escape() {
if [[ $# -ge 1 ]]; then
echo "$*"
else
cat # Read string from STDIN
fi | \
perl -pe 's/(?:(?<!\x1)|(?<!\\\[))(\x1b\[[0-9;]*[mG])(?!\x2|\\\])/\x1\1\x2/g'
}
Use it like:
$ echo $'\e[0;1;31mRED' | readline_ANSI_escape
Or:
$ readline_ANSI_escape "$string"
As a bonus, running the function multiple times will not re-escape already escaped control codes.
Upvotes: 1