c. tput
In today’s yak shave, we’ll be bebugging terminal prompt messed-up-edness.
You know how you see people with really cool terminal prompts in screencasts?
Gary Bernhart / Julia Evans / Dan Abramov / etc: 😎
Me: 👀
The problem is that messing with your terminal sometimes breaks things! Per always, a little patience, curiosity, and googling solves it. (but really — any excuse for a yak shave!)
Broken
export PS1="\[\u $(tput bold)$(tput setaf 4)\]\W\[$(tput sgr0)\] \$: "
Fixed
export PS1="\u \[$(tput bold)$(tput setaf 4)\]\W\[$(tput sgr0)\] \$: "
With help from:
For a long time, I was using liquidprompt to style my prompt. It worked pretty great!
But, it cost me a teensy bit of startup time when I opened a new terminal tab. Plus, I wanted to understand what was happening with my terminal, and control it myself!
So I decided to learn a little bit and use a prompt of my own design. “Foolish”, you might say. “Why not spend your time doing something useful instead?” Bah!
I took liquidprompt out of my config and added a little sumthin to my `.bashrc`:
export PS1="\[\u $(tput bold)$(tput setaf 4)\]\W\[$(tput sgr0)\] \$: "
Neat-o! Now my terminal looks like:
I started noticing that sometimes, especially when I scrolled backwards through my bash history, my prompt would get messed up.
My cursor wouldn’t show where I expected, the text got bumped all over, everything was pretty messed up. I could clear the screen with ctrl-l
or cmd-k
, which got me back to a working state. But I couldn’t scroll up and edit previous commands, and forget about searching bash history with ctrl-r
. 😭😭😭
Time to strap on the bug-stomping shoes and start googling!
🕵 🐛 👞
First, amusing: searches for PS1 console get results for the Sony gaming machine. PS1 variable gets results for the bash variable.
There’s a good guide to PS1 from Vivek Gite at nixCraft
Following the guide, you might echo $PS1
. I know I did.
And you might ask yourself: WTF is \\u@\h \\W]\\$
?
PS1
is a bash variable that sets the prompt\u
, \h
, \W
- all of these mean something to bash\u
is the current user’s username, \h
is the hostname up to the first .
, \W
is the basename of the current working directorytput
is freakin cool for styling terminal output (among other things)clear
, you might have ncurses)tput bold
prints out \033[1m$
This doesn’t show up in the terminal — it turns text to bold!
A critical piece of the list of PS1 options mentioned in the cyberciti post above:
\[ : begin a sequence of non-printing characters which could be used to embed a terminal control sequence into the prompt
\] : end a sequence of non-printing characters
This is how terminals get messed up!
Let me expand:
tput bold
), bash thinks your cursor is further than it should be\[
these guys \]
, bash does not count them for determining where your cursor goesNow that we’ve got a picture for how the PS1
variable works and how tput
is styling the prompt, we can debug!
My broken PS1
was:
export PS1="\[\u $(tput bold)$(tput setaf 4)\]\W\[$(tput sgr0)\] \$: "
Look! The \u
in my $PS1
is inside of these bad boys \[
\]
! That means bash thinks that the output of \u
(my username, robertcobb
) is non-printing characters.
Brain blast: bash won’t count my username as characters for the prompt 🤯
Now that I understand the bug, the solution is easy:
export PS1="\u \[$(tput bold)$(tput setaf 4)\]\W\[$(tput sgr0)\] \$: "
Moving the \u
outside of the non-printing section means that bash will count it towards my prompt characters. If it can get the count right, it won’t show my cursor in the wrong spot or otherwise ‘be all messed up’.
Now I can scroll through my bash history without my prompt getting b*rked 😌.