Why does this bash prompt sometimes keep part of previous commands when scrolling history?

30

16

My bash prompt, which I'll admit to have stolen from a few places and cobbled together, will sometimes add part of previous commands to its length when scrolling the bash history with up/down arrows.

For example, if my previous commands were:

ls
cd /home/caleb
vim .bashrc

When I was at my prompt and scrolled up twice it might look like:

$ vim .bcd /home/caleb

Where the first five characters are left over from last command.

Does anyone have any idea why this is happening, and how it can be stopped?

My prompt is set with this code (way to long to include here): https://gist.github.com/1679352

Caleb Thompson

Posted 2012-01-25T22:50:26.590

Reputation: 427

Have you already found the culprit in your prompt? I'm having the same issue. – acme – 2014-07-10T08:58:28.800

Yeah bash loses it on colors, and is unable to separate the length of strings with color escapes from the length of the visible string. This is what SiegeX was getting at.

I ended up switching to ZSH and using a different prompt. ZSH doesn't have the same issue. – Caleb Thompson – 2014-07-11T13:45:19.173

1

Both previous answer didn't get my problem solved, and did not give any explaination why this happened. Please check Custom Bash prompt is overwriting itself, if anyone have search to this point.

– D3Hunter – 2014-12-22T03:05:54.670

1Set PS1 to a value without the whole vcs crap and see what happens. That's my guess. – Daniel Beck – 2012-01-26T00:44:19.353

Answers

6

Somewhere your prompt is fubar. What usually happens is that your shell thinks its outputting non-printable term codes and expecting it to take up space. The best advice I can give you is to systematically add to (or take away from) your prompt until this behavior stops to isolate the code that is causing this issue.

SiegeX

Posted 2012-01-25T22:50:26.590

Reputation: 1 911

39

The color codes need to be wrapped in square brackets. The brackets inform bash that the enclosed text should not be printed

building on @Phreditor's example, this shows that any formatting done after the newline will result in the original issue:

export PS1="\n\n\[\033[01;33m[\w]\033[00m\n\033[0;90m\$ "

wrapping the format code in [] ensures that annoying behavior never happens:

export PS1="\n\[\[\033[01;33m\][\w]\[\033[00m\]\n\[\033[0;90m\]\$ "

The documentation: http://tldp.org/HOWTO/Bash-Prompt-HOWTO/nonprintingchars.html

Since PS1 formatting causes the value to be so long and hard to read I put the format codes in variables:

BYELLOW='\[\033[01;33m\]'
IBLACK='\[\033[0;90m\]'
PS_CLEAR='\[\033[0m\]'
export PS1="\n${BYELLOW}[\w]${PS_CLEAR}\n${IBLACK}\$ "

m79lkm

Posted 2012-01-25T22:50:26.590

Reputation: 491

3This should be the accepted answer. Did solve the issue. – Atcold – 2017-10-26T00:50:01.067

1It should be noted (because I failed to note it ;) ), that in that mess of backslashes and square brackets, the square brackets that follow the escape sequence \033 should NOT be escaped. Only the wrapping square brackets are to be escaped. – Benjam – 2018-01-31T16:29:22.460

Way to confusing for me to deal with all those special characters, using the first google result helped generate a working prompt exactly how I wanted it: http://ezprompt.net/

– Mallox – 2018-06-26T19:26:48.973

I have been wanting to customize my prompt colors for YEARS but never have since I always had this issue! I could never figure out why so I just stopped and kept everything white... I was just setting up a new computer and it finally dawned on me to actually Google the issue for once... So glad I did! Thank you for this wonderful lesson. – TylerH4 – 2019-06-13T17:20:42.357

8

I had the same problem and it was related to the color definitions.

In my case, I have a multi-line prompt (gives most space for current command regardless of path length displayed by prompt).

Bad version:

export PS1="\n\n\[\033[01;33m[\w]\n\033[00m\$ "

Good version:

export PS1="\n\n\[\033[01;33m[\w]\033[00m\n\$ "

\033[00m terminates the color. If it is after the new line (\n), it prevents proper redraw in the terminal, to overwrite previous commands with background color. Moving it behind the new line resolved the problem.

(using Terminal in Mac OS 10.8)

Phreditor

Posted 2012-01-25T22:50:26.590

Reputation: 181

This pinpointed the issue for me, while the current accepted answer was too generic. – Brian – 2014-12-20T17:38:34.263

This is the more precise answer and should be the winner (and was the solution to my problem as well). – craveytrain – 2015-04-24T15:49:16.467

the \n were the culprit for me too. Thanks! – mhulse – 2016-03-12T09:05:55.277

3

I actually think this has to do with a missing 'non-printing character' delimiter. I had exactly the same issue, but moving it before the newline (\n) didn't fix it. Instead I correctly surrounded all non-printing characters (here, colouring commands) with '\[' and '\]'.

Bad (works, but has the history-mashing problem described above):

PS1="\e[32m\u\e[35m@\e[32m\h \e[33m\w\e[36m\n\$\e[0m"

Good (surrounded all colour commands with '\[' and '\]' - does not show mashed command history):

PS1="\[\e[32m\]\u\[\e[35m\]@\[\e[32m\]\h \[\e[33m\]\w\[\e[36m\]\n\$\[\e[0m\]"

i.e. "\e[...m" --becomes--> "\[\e[...m\]"

And if you are putting this into something like SecureCRT to auto-send upon login to a system, you may have to double escape everything (put double backslashes everywhere) if auto-login system consumes the first backslash itself to determine the character to be sent:

PS1="\\[\\e[32m\\]\\u\\[\\e[35m\\]@\\[\\e[32m\\]\\h \\[\\e[33m\\]\\w\\[\\e[36m\\]\\n\\$\\[\\e[0m\\]"

i.e. "\..." --becomes--> "\\..."

(This is definitely true of SecureCRT and may be true of others, such as PuTTY or TeraTerm - testing required on your part.)

skeetastax

Posted 2012-01-25T22:50:26.590

Reputation: 101