Bash PS1: problem of line break with non-printable characters from an external command

I use an external command to populate a bash prompt that runs every time PS1 is evaluated. However, I have a problem when this command prints 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 to handle non-printable characters at the PS1 prompt is to wrap them in the escape sequence \[ and \] . The problem is that if you do this from an external command, these escape files are not processed 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 specific escape sequence that I can use from an external command to achieve the desired result? Or is there a way that I can manually tell the tooltip how many characters specify the width of the invitation?

Suppose that I can print anything that I like from an external command, and that this command can be pretty smart (for example, counting the characters in the output). I can also make the export PS1=... command as complex as necessary. However, color exit codes must come from an external command.

Thanks in advance!

+6
source share
2 answers

I could not say exactly why this works, but replace \[ and \] with the actual characters that bash generates from them at the prompt:

 echo -e "\001\033[32m\002cheese\001\033[0m\002" 

[I found out about this from some Stack Overflow post I can't find right now.]

If I were to assume that bash replaces \[ and \] with two ASCII characters before executing the command embedded in the prompt, so by the time green_cheese.sh is green_cheese.sh it is too late for bash to properly process wrappers, and therefore they are processed literally. One way to avoid this is to use PROMPT_COMMAND to dynamically create the query, and not to PROMPT_COMMAND executable code into the value of PS1 .

 prompt_cmd () { PS1="$(green_cheese.sh)" PS1+=' \$ ' } PROMPT_COMMAND=prompt_cmd 

Thus, \[ and \] are added to PS1 when it is defined, and not when it is evaluated, so you do not need to use \001 and \002 directly.

+13
source

I suspect that if you repeat the value of $PS1 after the first example, you will see that its meaning is the word "cheese" in green. (At least this is what I see when I run your example.) At first glance, this is what you want - the word "cheese" in green! In addition, what you really wanted was the word โ€œcheeseโ€, preceded by exit codes that generate green. What you did using the -e flag for an echo returns a value with escape codes already evaluated.

This works for specifying colors, but as you discovered, it manipulates โ€œnon-printable sequenceโ€ markers into something that the $PS1 interpreter doesn't understand correctly.

Fortunately, the solution is simple: clear the -e flag. echo will then leave the escape sequences intact, and the $PS1 interpreter will do the right thing.

-1
source

Source: https://habr.com/ru/post/972493/


All Articles