
Your Bash Prompt Needs This - jonisalonen
http://jonisalonen.com/2012/your-bash-prompt-needs-this/
======
eridius
I used to do this in my prompt, but it caused more problems than it solved,
since sometimes programs actually put legitimate output on the last line
without a terminator.

The simpler fix is just to notice that your prompt has shifted over (it's
almost impossible not to notice) and just hit return before doing anything.

~~~
mgedmin
I added a newline (\n) to the beginning of my prompt. This way I never lose
program output -- and also it's easier to see where previous commands begin
and end in the scrollback buffer.

~~~
eridius
You also get tons of blank lines, right? That would annoy the heck out of me.

~~~
spiffytech
My prompt is five lines tall, including three blank lines. I did that, along
with some bright green coloring, to make the prompt easier to spot as I
rapidly scroll up through a mountain of output from my last command.

zsh prompt:

PROMPT='

%{$prompt_default_color%} %~ %*
%{${fg[$prompt_user]}%}%n%{$prompt_default_color%}@%{${fg[$prompt_host]}%}%M%{$prompt_default_color%}
${vcs_info_msg_0_}_

$ %{${fg[default]}%}'

------
viraptor
Alternative - use zsh which doesn't suffer from this. (or from deleting lines
with no line terminator - it inserts it's own "%" sign with inverted colour
and a \n when that happens)

~~~
jlongster
+1. I don't really understand why you wouldn't use zsh, or something more
powerful than bash.

~~~
maratd
Because bash is the standard on Linux and every component you add introduces
additional complexity and instability. It's fine to add stuff to your home
machine, but you need to be careful with adding things to a server or a work
environment. Bash is good enough for almost everything.

~~~
endlessvoid94
Find me a real world case where switching from bash to zsh was a bad idea.

~~~
rwg
Well, I switched from csh to zsh and almost got arrested.

While a senior in high school (~15 years ago), I was also enrolled at the
local university and taking a few 1000- and 2000-level Math and CS courses.
About halfway into the spring semester, my account on the CS department's
crusty old Sun box was locked, and my CS professor that semester told me to
report to the system administrator's office after class.

When I arrived at the system administrator's office, the department's system
administrator and the department head were waiting for me. The sysadmin
immediately (and angrily) said that if this were anywhere but a university,
he'd see that I was thrown in jail. When I asked what he was talking about, he
turned to his computer, banged on the keyboard for a bit, and turned the
massive CRT so I could read it.

On his screen was an e-mail I had sent him the semester before asking that he
change my shell from /bin/csh to /usr/local/bin/zsh. (Solaris of that vintage
didn't have chsh, so I couldn't do it myself.)

The sysadmin was absolutely convinced that zsh gave me "elevated system
privileges", even though he was the one that changed my passwd entry and
presumably was the one who compiled and installed zsh in the first place.

When I argued that /usr/local/bin/zsh didn't have the suid or sgid bits and
therefore gave me no more access to the system than any other shell, the
department head scolded me for arguing with the (experienced, wise) sysadmin.

The sysadmin changed my shell back to csh, and the department head made me
sign a document stating that I wouldn't change my shell back to zsh or try to
"further gain administrative access" to the system.

On the drive home, I idly wondered whether going to (a different!) college
full-time in the fall was really such a hot idea...

~~~
snprbob86
With the caveat that you should always pick your battles...

You should have never signed that. Even if you struck the word "further", it'd
probably be seen as an admission of guilt in court.

------
freshbreath
What if a program prints text without a newline at the end, then exits? It's
possible and it would be confusing to not see that last line.

    
    
        cout >> "Hello world"; // with no endl.
    

Prepending the prompt with a new line might be a better idea than over-writing
the current line.

~~~
arjunnarayan
Yes. I have a two line bash prompt: the first line with a whole bunch of info
like the exit status of the last command, the number of background jobs, the
hostname, current username (very useful when you have 5 different ssh sessions
to different machines), and the current working directory. In real world usage
I have experienced almost no loss of utility from only having 50% of my
command history on screen. In fact, given how many commands are just
ls,whoami,jobs,pwd, that info gets condensed into one line.

~~~
TimothyFitz
Cool! Do you mind posting your PS1 so other people can try out your config?

~~~
arjunnarayan
Here's the PS1:

    
    
      PS1="\[\e[32;1m\]\[\e[37;1m\]\`if [ \$? = 0 ]; then echo \[\e[33m\] :\)\[\e[0m\]; else echo \[\e[31m\] X\(\[\e[0m\]; fi\`\[\e[32;1m\] \[\e[32;1m\](\[\e[37;1m\]\h:\u\[\e[32;1m\])-(\[\e[37;1m\]\j\[\e[32;1m\])-(\[\e[37;1m\]\w\[\e[32;1m\])\n\[\e[0m\]"
    

Here's how it appears:

    
    
       :) (seas456:narayana)-(0)-(~/personal)
      [this line is where your cursor blinks; notice no symbol at the start of this line]
    

You can't see the colors here. The smiley face turns into a bright red frowny
face if the exit code of the last job is nonzero.

~~~
jamii
It looks like the your markup got mangled a little. Would you mind posting a
gist?

------
CGamesPlay
Put a blank line at the beginning of your PS1 instead. This has the added
benefit of clearly separating every command. My PS1 actually is this:

    
    
      rpatterson@rpatterson-tba 04/27/2012 01:24 PM ~
      $ 
    

This gives me a full row to type a command, and lets me see how long ago the
last command finished. Each of those components is bold and colored
differently.

~~~
prakashk
I do this too. It helps me to have a blank line between invocations of
different commands.

    
    
        [prakash@kaveri 16:39:05 ~ :) ]
        >> sleep 10
        ^C
    
        [prakash@kaveri 16:39:18 ~ :( ]

~~~
natep
So...your interrupted 'sleep 10' took 13 seconds?

~~~
CGamesPlay
No, the time between when the first PS1 was printed and when he pressed ^C was
approximately 13 seconds.

~~~
natep
Of course, my bad.

------
pavel_lishin
Nitpick - shouldn't it be

    
    
        PS1="\[\033[G\]$PS1"
    

instead of

    
    
        $PS1="\[\033[G\]$PS1"

~~~
delinka
Yes, you are correct. I think it's better than nitpicking when it makes the
code run correctly.

------
saurik
I honestly cannot replicate either of these behaviors, even using the OS X
Terminal application (which definitely causes serious cursor synchronization
issues with complex prompts due to incorrect terminal emulation: use iTerm2
instead), and even using an old version of bash (tested on both Linux and OS
X).

A) When I hit ^C, I am always seeing a newline occur after the ^C and before
my prompt is redrawn. I have tried this with cat (blocked on read) and ssh
(blocked on password).

B) When I purposely attempt to cause this (using echo -n and interpreting "a
very long command" to mean "long enough that it wrapped to the next line"),
hitting up redraws and overwrites part of the prompt in order to guarantee
that the position of the prompt will edit correctly.

~~~
jamii
I have had this problem before, usually when using a repl that gets abnormally
terminated. I don't know exactly what causes it and I haven't been able to
replicate it deliberately. Long commands alone don't seem to trigger it.

------
ams6110
Seems like ^L usually clears things up when this happens.

~~~
ajross
That's what I came to post. Yes, the terminal gets mixed up because it handled
input that bash didn't see. And that's annoying (really it's a bug, just one
so ancient no one is interested in fixing it anymore).

But terminal corruption used to be far more common (line noise, etc...) and
bash has a built-in escape for this. Ctrl-L (chosen for the analogy with form-
feed/"vertical tab" on a printer) will blank the screen and redraw your
current edit environment at the top.

~~~
ralph
I don't see it as a bug; the shell shouldn't get to see what was written to
the terminal?

BTW, it's the readline library that handles the Ctrl-L key binding to clear
the screen rather than bash per se.

    
    
        $ bind -p | grep '\\C-l'
        "\C-l": clear-screen
        $

------
runjake
All too often, this "erases" legitimate output. I just prefix my prompt with a
\n, personally.

------
CJefferson
Recently, I have really wished for a "better terminal". Particularly as my
number of processors go up, I want to be able to start a program in the
background and not have it's output all over the screen. I've tried various
solutions (redirect to temp file -- have to remember where it is, keep
starting new tmux sessions, end up with too many windows most of which I don't
want). I feel there should be something better. Personally, I take a GUI
solution, where programs look more like a tree, and I can easily explore /
close / duplicate branches.

~~~
sliverstorm
Have you tried gnu screen? It isn't a gui interface, so you have to learn a
few hotkeys, but it's one of the better options.

~~~
CJefferson
tmux is similar to screen. I can keep opening hotkeys to open new windows to
run commands in, but then I have to remember to go back to those windows to
look at the results of those commands, etc.

It doesn't really help me "maximise my processor usage" I find.

~~~
sliverstorm
So what you are saying is you want a more powerful version of regular shell
background capabilities? You don't want output to interrupt your interactive
session, but you don't want to have to _remember_ to visit the output later.

Do I have this right?

~~~
CJefferson
I think so. I might not know what I want until I have it, or don't have it :)

I just went through the following steps recently:

1) Put more things in the background with '&' - but if they have a lot of
output they make your terminal usuable.

2) I could ' >t 2&>1 & ' , but then I have to remember to check t when the
process finishes, and end up with lots of tiny files everywhere.

3) I could just send output to /dev/null , but then maybe I care what it was
if the process fails.

~~~
natep
Sounds like #2 could work if you had some sort of desktop notification system.
Then you could write a small script that runs your command line with stdout
and stderr redirected to temp file(s), and then alerts you when the process is
done, and what the temp filenames are. You could check on your running jobs
with 'ps -C scriptname'

Or maybe opens them in $EDITOR...like this (I can't get it to work when $* has
a pipe in it, unfortunately)

    
    
        #!/bin/bash
        out1=`tempfile -d $HOME/logs`
        out2=`tempfile -d $HOME/logs`
        $* >$out1 2>$out2
        $EDITOR $out1 $out2 # Replace this with call to notification app and/or logic based on $?/size of $out2

------
ilya2
zsh is relatively large compared to bash. and bash is large compared to sh,
rc, tcsh, etc. if there are space and memory constraints, size is relevant.

the path to "user-friendly" shell nirvana (i.e. interactive use, not scripts)
can be achieved through use of a library like editline, without installing a
huge, "kitchen sink" package like zsh... if size is an issue. make the shell
cmd line behave like the editor you know well.

------
werkshy
Post says $PS1="\\[\033[G\\]$PS1"

But the first $ is wrong, it should read PS1="\\[\033[G\\]$PS1"

~~~
georgecmu
Even

    
    
        export PS1="\[\033[G\]$PS1"

~~~
lotheac
I don't think exporting PS1 is a good idea. Child processes don't need it and
if I launch a different shell with different PS1 semantics I get a broken
prompt instead of whatever the default for that shell is.

------
xyzzyz
Even better, if you want to edit a long command, use C-x C-e (remember to have
EDITOR set to your editor of choice).

~~~
calloc
I never knew this, this is absolutely going to be a timesaver!

------
ralph
Sorry, I think it's a problem not worth solving; it's helpful to know this has
occurred by the state the screen is in. If you want to solve it correctly
then, since it's also common to have the cursor left bereft in the middle of a
screen of text,

    
    
        PS1='\['"$(tput cr)$(tput ed)"'\]$ '
    

is better since it clears to the end of the screen, e.g. try

    
    
        seq 1000 | fmt; tput cup 10 20
    

with and without it.

But the thing is, with either that approach or the one in the article, you're
wiping out what may be useful; that unfinished line causing PS1 to be pushed
along may have vital data on it, data that's hard to re-create.

------
shabble
In my past experience, prompt/history corruption is quite often due to
missing/incorrect use of \\[ and \\] around all the non-printing sequences
(colours, formatting, etc), which cause Bash to compute the length of the
prompt incorrectly, and cause redrawing woes.

Worth double-checking, anyway. I've occasionally pondered some sort of prompt-
lint/validator given the reams of dubious examples out there, and problems
people face when customising their own.

------
Estragon
I just do most of my bash work in emacs shell mode.

~~~
dustingetz
me too for a couple months now - there are a lot of rough edges - any tips? i
have serious prompt issues, i have intermittently malformed colors. is your
configuration on github?

turns out i'm willing to tolerate a lot of pain to have emacs operations in a
shell buffer, haha

~~~
tikhonj
What kind of prompt issues do you have? I've set my Emacs up so that each
shell has a prompt in the form name:directory> where name is the buffer name
and directory is the current directory, and both name and directory are in
different colors, and it all works well.

As far as colors go, shell mode does its own highlighting. I used to have
problems with ANSI code colors, but they have been working properly recently.
(I just tried ls --color=always which worked as expected, unexpectedly.)

Which version of Emacs are you on?

Note that this is all without any configuration. The only thing I did was add
a command for opening a new shell in the current directory which turned out to
be _extremely_ useful. It even works for remote files, so now I use shell mode
for almost everything.

------
kibibyte
This has a side-effect that I don't like. Python's virtualenv, once activated,
places the string '(venv)' (assuming you named it 'venv') immediately before
your prompt to let you know that it is active in this terminal. However, this
export hides this modification, and it makes it difficult for me tell whether
the venv is active or not.

~~~
mgedmin
Personally I do not use virtualenv activation. Instead I prefer to explicitly
launch Python and/or scripts with bin/python, bin/scriptname etc., either with
my current working directory in the virtualenv, or by creating a symlink ./bin
-> .virtualenv/bin in the project root.

------
seles
Couldn't you just hit enter after hitting control-C to bring up a new prompt
below the one with the ^C in it?

------
matheusalmeida
One could comment the "very long command" with # and it would appear in the
history... no hacks.

~~~
adavies42
this is hotkeyed to Meta-# by default

(one of the readline features i rediscover every three months or so and
promptly forget)

~~~
matheusalmeida
Tested and it works brilliantly... it's definitely faster than C-a # RET...
Thanks for the tip.

~~~
adavies42
it's fully customizable too. e.g. if you work in a LISP REPL and use rlwrap to
provide readline functionality, you could put this in your ~/.inputrc:

    
    
        $if lisp
                set comment-begin ;
                M-;: insert-comment
        $endif

------
dredmorbius
<http://tldp.org/LDP/LGNET/122/lg_tips.html>

I set mine to standard for successful output "[user@host:truncated path]$ ".

Having my shell smile at me all the time makes me think it's up to something.

------
fictorial
Hmm, I don't have this issue. Perhaps because I use a two-line prompt?

    
    
        export PS1="\n\W\$(parse_git_branch) $ "
    
        parse_git_branch() { git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'; }

~~~
Aissen
You use a custom git parse branch, while git has a much more powerful prompt
function : __git_ps1 . It's readily available in git's default
bash_completion.d file. It shows the current branch, but also the state of the
git tree (during rebase, am, bisecting, cherry-picking, etc.)

------
mvanga
When I see this, I tend to automatically hit Ctrl+L to clear the screen and
re-position the prompt. Quick and easy. I scroll up if I need to study the
output further.

------
dbbolton
I don't have this problem (even though I don't use bash) since the first
character in my prompt is a newline. I think it makes things easier to read in
general.

------
keeperofdakeys
I've always found putting $? handy. This is the exit status of the last
command, and when non-zero means the program wasn't successful or encountered
an error.

------
g3orge
or you just configure a two line prompt (with a \n).

~~~
mooism2
That means a blank line after most commands' output, and I find that
unsightly.

Is there any way of getting bash to only output a '\n' if the cursor isn't
already at the start of a line?

~~~
mturmon
Recommendation: Try it for a week or so, and you may not go back. I've found
it to be helpful to have more space between commands.

------
gosub
Why isn't the last line in shells dedicated only to the prompt? The commands'
output could scroll in the remaining lines.

------
christphrdunder
alternate solution using readline: set echo-control-characters Off

------
jcubic
When you use this in your prompt this will not show any result

$ echo -n foo bar

------
werner34
wouldn't typing 'reset' fix this?

~~~
elliottcarlson
Or just hitting enter to get a new line - this is trying to make a more
permanent solution to this common issue.

------
zobzu
zob ~ ⚡ bob^C

zob ~ ⚡ cat

^C zob ~ ⚡

default bash settings real termina, like xterm this is bash of course.

and its better than ^C is not erased.

~~~
saurik
Can you say more about the testing configuration you are using? With OS X
10.6.8, xterm 251, bash 3.2.48(1), and with no .bashrc, and after trying to
set my PS1 to match yours (failing, as the lightning bolt came up as an o with
an umlaut), I get the following behavior for the same test:

    
    
        saurik ~ ö bob
        saurik ~ ö cat
        ^C
        saurik ~ ö

~~~
zobzu
your term looks ok im using linux and konsole bash 4.2.24(2)-release

the lightning bolt is just an utf8 fancy char

this is my PS1 if you like it: \\[\e[0;32m\\]\u\\[\e[m\\]
\\[\e[1;34m\\]\w\\[\e[m\\] \\[\e[1;33m\\]⚡\\[\e[m\\] \\[\e[1;37m\\]

------
xiafei
greate

------
strela
anyway, who's using bash nowadays? there's zsh...

------
ggchappell
Very helpful tip! Thanks for posting.

