When I use my terminal (iTerm 2 Mac) with my PS1 set to "\[\e[38;5;117m\W \e[39;38;5;104m\$\e[39;0m\] " and I use the arrow keys to go through my bash history it sometimes changes my prompt from ~ $ to just the first character of it and whatever command I'm looking at. For example, going to rvim .bashrc from randomDir $ ls. This problem also persists in the default terminal app.
\W and \$ should not go inside the \[...\], since bash will know how much space each takes up on the terminal.
PS1="\[\e[38;5;117m\]\W \[\e[39;38;5;104m\]\$\[\e[39;0m\] "
Only the characters that make up the ANSI escape sequence (which only instruct the terminal to change colors, without displaying a single additional character) are enclosed in \[...\].
Putting them inside \[...\] tells bash to ignore their contribution to the length of the prompt, leading to incorrect redraws.
Related
In the following scenario, my bash prompt looks like this:
Username#Hostname ~ $
If I type any number of characters, and then press the delete button one-too-many times, it will clear the entire line. For example:
Username#Hostname ~ $ ls
then I delete s
Username#Hostname ~ $ l
then I delete l
|
I'm then left with my cursor without any sort of prompt. I can type up commands normally and everything seems to function fine--but why does the prompt disappear? Is there a way to stop this behavior?
If you are using escape sequences to color (or otherwise add content) to your prompt without marking the escapes as "non-printing", bash will lose track of the column, and result in behavior like this.
bash's manual suggests that you put nonprinting characters in your prompt within \[ and \] markers.
For the given example
PS1='\[\033[1;32m\u#\h\[\033[00m \[\033[1;34m\w $\[\033[00m '
a possible improved version would be
PS1='\[\033[1;32m\]\u#\h\[\033[00m\] \[\033[1;34m\]\w $\[\033[00m\] '
I have written a small program that emits a command line prompt with some Git info. I use ANSI escape sequences to color it, and it looks something like this:
However, whenever I do tab completion or a search, zsh inserts several spaces after the prompt:
It seems to be inserting a space for each escape code character emitted by the prompt, since removing the color codes eliminates this behavior. Why is zsh doing so, and how can I stop this?
The actual character sequence emitted by my prompt program for this example is (assuming \e represents character 033)
~/s/promptd [\e[36mmaster \e[33m±\e[31m?\e[39m]
The relevant portion of my .zshrc is:
setopt PROMPT_SUBST
setopt PROMPT_PERCENT
PROMPT='%B$(promptd) %%%b '
After doing some additional research, the ZSH Prompt Expansion docs indicate that escape literals need to be enclosed in %{...%}.
This is bothersome since now I have to output those conditionally if I want the prompt program to work in other shells, but it seems to correct the behavior shown above.
I started using this code from Mark Dotto (http://markdotto.com/2013/01/13/improved-terminal-hotness/) to make my terminal is bit sexier.
I just copied the code without editing it, so in my .bash_profile I added:
export PS1='\[\e[0:35m⌘\e[m \e[0:36m\w/\e[m \e[0:33m`git branch 2> /dev/null | grep -e ^* | sed -E s/^\\\\\*\ \(.+\)$/\(\\\\\1\)\ /`\e[m\]'
Everything's working, but there is a weird thing: when I type 3 characters or less then I hit backspace, it deletes everything, even the informations on the left (the path and git branch).
This could be okay, but the problem is that when I keep typing after that, the command I started typing is still here (but hidden).
I guess you didn't understand so I'll try to show some code:
# this is what my prompt looks like
~/my/path/ (branch) |
# I start typing a command
~/my/path/ (branch) ls|
# now I hit backspace once
|
# everything is removed
# but if I type something else then hit return
git st|
# it throws an error as the `l` from the previous command is still here
-bash: lgit: command not found
I have absolutely know idea how this bash_profile works, anybody can help? Thanks
there appears to be some incorrect syntax in your PS1 variable that's causing some unexpected errors. try this revision instead:
export PS1='\[\e[36m\]\w \[\e[33m\]`git branch 2> /dev/null | grep -e ^* | sed -E s/^\\\\\*\ \(.+\)$/\(\\\\\1\)\ /` \[\e[0m\]'
(note: i left the git ... grep ... sed pipeline alone and only edited the parts related to the prompt itself.)
edit - take out the 0: parts and the colors actually work. (i.e. \[\e[36m\] instead of \[\e[0:36m\])
and here's a breakdown of what's going on there:
\[\e[36m\] - this block sets a foreground text color (light blue/tealish)
\w - current working directory
\[\e[33m\] - sets a different text color (yellow)
git ... grep ... sed - retrieves your current git branch
\[\e[0m\] - resets the text color to white so you're not typing commands in yellow
if you don't care about colors, prompts are a fairly trivial thing. the color blocks make it a bit more complex, and (as you've seen) error prone.
First of all: Make sure you are using the BASH shell.
I am on Mountain Lion on a MacBook and the PS1 command sort of, kind of works. My prompt looks like this:
⌘ ~/SVN-Precommit-Kitchen-Sink-Hook.git/ (master) _
I guess the question is what do you want your prompt to do. BASH prompts can embed a whole bunch of escape sequences that can do all sorts of neat things that in Kornshell would take a wee bit of hacking.
Type man bash on the command line, and find the PROMPTING heading. You should see something like this:
When executing interactively, bash displays the primary prompt PS1 when it is ready to read a com-
mand, and the secondary prompt PS2 when it needs more input to complete a command. Bash allows these
prompt strings to be customized by inserting a number of backslash-escaped special characters that
are decoded as follows:
\a an ASCII bell character (07)
\d the date in "Weekday Month Date" format (e.g., "Tue May 26")
\D{format}
the format is passed to strftime(3) and the result is inserted into the prompt string;
an empty format results in a locale-specific time representation. The braces are
required
\e an ASCII escape character (033)
\h the hostname up to the first `.'
\H the hostname
\j the number of jobs currently managed by the shell
\l the basename of the shell's terminal device name
\n newline
\r carriage return
\s the name of the shell, the basename of $0 (the portion following the final slash)
\t the current time in 24-hour HH:MM:SS format
\T the current time in 12-hour HH:MM:SS format
\# the current time in 12-hour am/pm format
\A the current time in 24-hour HH:MM format
\u the username of the current user
\v the version of bash (e.g., 2.00)
\V the release of bash, version + patch level (e.g., 2.00.0)
\w the current working directory, with $HOME abbreviated with a tilde
\W the basename of the current working directory, with $HOME abbreviated with a tilde
\! the history number of this command
\# the command number of this command
\$ if the effective UID is 0, a #, otherwise a $
\nnn the character corresponding to the octal number nnn
\\ a backslash
\[ 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
Let's take a simple prompt. I want to display my user name, the system I'm on, and my current directory. I can set PS1 like this:
PS1="\u#\h:\w$ "
This will give me:
david#davebook:~$ _
The \u is my user name (david), the \h is my machine name (davebook), and the \w displays the current directory I'm in relation to my $HOME directory.
You can also embed commands in the prompt too:
PS1="\$(date) \u#\h:\w$ "
Now the date and time will be embedded in my prompt:
Fri Feb 1 09:45:53 EST 2013 david#DaveBook:~
Sort of silly (I should have formatted the date. Besides, BASH already has built in sequences for the date), but you get the idea.
I recommend that you build your own damn prompt. If you're a git user, and you're using command lines comfortably, you can probably make a nice prompt yourself to look the way you want. You can use the \$(command) syntax to include interactive commands that get executed with each new PS command. You can use ANSI escape codes to color different parts of your prompt, or make them do fantastic stuff.
Build your prompt slowly and bit-by-bit. Create a shell script that will set PS1, and source it in like this:
$ echo "PS='\u#\h:\w\$ " > prompt.sh
$ chmod a+x prompt.sh
$ . prompt.sh
Then, add more and more features to your prompt until you get it to work the way you want.
Personally, I avoid over fancy prompts simply because they tend to fall apart sometime when you least expect it. For example, I use VI sequences for editing, and that prompt simply falls completely apart whenever I try to edit my command line.
Fancy prompts remind me of programs like Talking Moose which are really cool for the first few minutes, then start getting really, really annoying after that.
I have this code to color my terminal:
export PS1="\e[1;30m\][\e[\e[1;30m\]\e[1;33m\] \u#\H \[\e[1;32m\]\w\[\e[0m\] \e[1;30m\]]\n[\[ \e[1;31m\]\T\[\e[0m\]\e[1;30m\] ] > \e[37m\]"
But I have one problem, when text should be in the new line it overwrites the first line.
Example:
In order for bash to figure out how much screen space your prompt takes up (and therefore where the actual command line starts), you have to enclose the non-printing parts of the prompt in \[...\]. Mostly, that means escape sequences like \e[1;30m need to be written as \[\e[1;30m\]. You have some \['s and \]'s in your prompt, but they're in the wrong places, which is making bash very confused. Finding all the printing and non-printing parts of a prompt as complex as yours is not trivial, but I think this gets it right:
export PS1='\[\e[1;30m[\e[\e[1;30m\e[1;33m\] \u#\H \[\e[1;32m\]\w\[\e[0m\] \[\e[1;30m\]]\n[ \[\e[1;31m\]\T\[\e[0m\e[1;30m\] ] > \[\e[37m\]'
When cycling through statements entered to the console, I occasionally find that the text I entered isn't refreshed and the prompt is moved to the right.
My original, intended prompt: http://cl.ly/image/04080N260L1V.
What happens after hitting the Up and Down arrows about a dozen times: http://cl.ly/image/1n3S2K31340R.
In case the screenshots aren't clear, the underlined text (in this case, "vim ~/.bas") is getting "added" to the prompt. I can't delete it out. However, if I delete as much as I can, clearing any text after the prompt, and hit Enter, I'm greeted with my clean, original prompt again: http://cl.ly/image/2O1h1Z2y0n2I.
Here's what ~/.bash_profile contains:
# Simpler bash prompt in Terminal.app
promptColor="\e[1;34m"
endColor="\e[m"
#export PS1='\e[0;36m\w$ \e[0m'
export PS1="$promptColor\w$ $endColor"
# Syntax highlighting for commands like `ls` and such
alias ls="ls -G"
# PATH ammendment to put Homebrew-installed apps in front of system-provided ones
homebrew=/usr/local/bin:/usr/local/sbin:/usr/local/share/npm/bin
export PATH=$homebrew:$PATH
I've narrowed the culprit down to the PS1 variable. (You can see I've tried this a few different ways.) Based on what I've read, I'm using the color codes correctly.
Any help would be fantastic. Thanks.
This is a FAQ. In order for Bash to be able to compute the display length of the prompt correctly, any non-printing sequences such as color codes need to be inside a \[...\] sequence.
I think you want:
promptColor='\e[1;34m'
endColor='\e[m'
export PS1="$promptColor"'\w$ '"$endColor"
(Notice all the subtle changes from double to single-quotes)
The problem is that bash is doing expansion on the following when they need to be interpreted explicitly:
\e[1;34m
\w$
\e[m
Single-quotes and double-quotes mean different things in shell: Strong Quoting vs. Weak Quoting.
I would also just copy and paste the lines with escaped characters and modify them (note that they aren't the same as literal representations)