Reputation: 7315
When putting ANSI color codes in PS1
, they need to be surrounded with \[\]
or else the prompt can get confused about where the editable part of the line starts. However, when a subcommand ($()
) prints colors, the \[\]
escapes are always being written literally to the prompt...and with long enough commands in my history, the prompt gets confused.
Here's an example:
ps1test() {
ps1sub() {
printf '\[\033[32m\]Hello!\[\033[0m\]'
}
PS1='$(ps1sub) \$ '
}
Expected:
$ ps1test
Hello! $
Actual (bash
installed by Git for Windows):
$ ps1test
\[\]Hello!\[\] $
How can I get my shell to interpret the \[\]
escapes from a subcommand?
Upvotes: 1
Views: 485
Reputation: 48794
If you're trying to create a dynamic prompt, you're likely to have an easier time setting the PS1
value via a function invoked as PROMPT_COMMAND
, e.g.:
ps1test() {
ps1sub() {
printf '\[\033[32m\]Hello!\[\033[0m\]'
}
PS1="$(ps1sub)"' \$ ' # notice the double-quote
}
PROMPT_COMMAND=ps1test
This renders correctly as Hello! $
for me.
I use prompt.gem to render my prompt, you can take a look at how it configures PROMPT_COMMAND
for some inspiration.
Upvotes: 2
Reputation: 212178
This is exactly the right use case for eval
:
ps1test() {
ps1sub() {
printf '\[\033[31m\]Hello!\[\033[0m\]';
};
eval PS1="'$(ps1sub) \$ '";
}
Upvotes: 0
Reputation: 123400
Only \[
s in the literal string are interpreted. \[
s resulting from embedded expansions are not.
The easiest way to get around it is to have PROMPT_COMMAND
set a PS1
to a new literal value each time:
updateps1() {
ps1sub() {
printf '\[\033[32m\]Hello $RANDOM!\[\033[0m\]'
}
PS1="$(ps1sub) \\\$ "
}
PROMPT_COMMAND='updateps1'
Upvotes: 3