I am using an external command to populate my bash prompt, which is run each time PS1 is evaluated. However, I have a problem when this command outputs non-printable characters (like color escape codes). Here is an example:
$ cat green_cheese.sh
#!/bin/bash
echo -e "\033[32mcheese\033[0m"
$ export PS1="\$(./green_cheese.sh) \$"
cheese $ # <- cheese is green!
cheese $ <now type really long command>
The canonical way of dealing with non-printing characters in the PS1 prompt is to enclose them in \[
and \]
escape sequences. The problem is that if you do this from the external command those escapes are not parsed by the PS1 interpreter:
$ cat green_cheese.sh
#!/bin/bash
echo -e "\[\033[32m\]cheese\[\033[0m\]"
$ export PS1="\$(./green_cheese.sh) \$"
\[\]cheese\[\] $ # <- FAIL!
Is there a particular escape sequence I can use from the external command to achieve the desired result? Or is there a way I can manually tell the prompt how many characters to set the prompt width to?
Assume that I can print anything I like from the external command, and that this command can be quite intelligent (for example, counting characters in the output). I can also make the export PS1=...
command as complicated as required. However, the escape codes for the colors must come from the external command.
Thanks in advance!
I couldn't tell you exactly why this works, but replace \[
and \]
with the actual characters that bash
generates from them in your prompt:
echo -e "\001\033[32m\002cheese\001\033[0m\002"
[I learned this from some Stack Overflow post that I cannot find now.]
If I had to guess, it's that bash
replaces \[
and \]
with the two ASCII characters before executing the command that's embedded in the prompt, so that by the time green_cheese.sh
completes, it's too late for bash
to process the wrappers correctly, and so they are treated literally. One way to avoid this is to use PROMPT_COMMAND
to build your prompt dynamically, rather than embedding executable code in the value of PS1
.
prompt_cmd () {
PS1="$(green_cheese.sh)"
PS1+=' \$ '
}
PROMPT_COMMAND=prompt_cmd
This way, the \[
and \]
are added to PS1
when it is defined, not when it is evaluated, so you don't need to use \001
and \002
directly.