In bash, how do I encode zero-width sequences into PS1, when those sequences are coming from stdout of an external process or function? How do I implement writes-prompt-sequences-to-stdout
so that it can emit multi-colored text to the prompt?
PS1='$( writes-prompt-sequences-to-stdout )'
I know that, when writing a bash PS1 prompt, I must wrap zero-width sequences in \[
\]
so bash can compute correct prompt width.
PS1='\[\e[0;35m\]$ \[\e[00m\]'
bash does not print the \[
\]
and understands the prompt is only 2 characters wide.
How do I move those sequences into an external function? The following does not work, my prompt looks like \[\]$ \[\]
, even though I can run render-prompt
and see it writing the correct sequence of bytes to stdout.
PS1='$( render-prompt )'
function render-prompt {
printf '\[\e[0;35m\]$ \[\e[00m\]'
}
Moving the printf call into PS1 does work:
PS1='$( printf '"'"'\[\e[0;35m\]$ \[\e[00m\]'"'"' )'
I theorized, perhaps bash is scanning the PS1 string before execution to count the number of zero-width bytes. So I tried tricking it by encoding [] sequences that aren't printed, but it correctly ignores the trick.
PS1='$( printf '"'"'$$$$$'"'"' '"'"'\[\e[00m\]'"'"' )'
My question:
How do I write \[
\]
sequences to stdout from a function or binary that is invoked via PS1?
Best Answer
I figured it out. Bash special-cases
\e
,\[
, and\]
within PS1. It coverts\e
to an escape byte,\[
to a1
byte, and\]
to a2
byte. External commands must write1
and2
bytes to stdout.According to ASCII, these encode "start of heading" and "start of text."
http://www.columbia.edu/kermit/ascii.html
Here's a working example, which relies on printf converting
\
escapes within the first positional parameter into the correct bytes: