amflare
amflare

Reputation: 4113

Why does bash prompt (PS1) append ghost commands?

I have some custom code that adjusts my prompt to display like this:

(git-branch):~/t/r/u/ncated-dir$

Sometimes when I am scrolling through previous commands with the arrow keys in my terminal, the prompt will capture ~6-7 characters and append it to the prompt.

The problem as seen is that this:

(master):~/p/test$ <scroll up/down through commands here>

Becomes this:

(master):~/p/test$ git pus<keep scrolling up/down through commands here>

Which leads to a prompt that looks like this when I'm done:

(master):~/p/test$ git puscd public/app/css
(master):~/p/t/p/a/css$ 

So obviously it is not imparing or breaking the execution, but it is still annoying.

My .bash_profile looks like this:

source "$HOME/bin/git-prompt.sh"
source "$HOME/bin/truncate.sh"

PS1="\$(git_prompt)" # prints current branch
PS1+="\[$COLOR_WHITE\]:\[$COLOR_BLUE\]\$(truncate)" # directory path
PS1+="\[$COLOR_WHITE\]\$\[$COLOR_RESET\] " # '#' for root, else '$'
export PS1

I think git-prompt.sh might be the issue since the problems goes away whenever I comment out that line in .bash_profile. But I can't figure out why. It should not be running (and thus altering PS1) until I hit enter. So I'm not sure how I'm getting ghost commands on the prompt.

#! /bin/bash

COLOR_RED="\033[1;31m"
COLOR_YELLOW="\033[1;33m"
COLOR_GREEN="\033[1;32m"
export COLOR_GREY="\033[1;90m"
export COLOR_BLUE="\033[1;34m"
export COLOR_WHITE="\033[0;37m"
export COLOR_RESET="\033[0m"

function git_prompt {
  local git_status
  local color
  git_status="$(git status 2> /dev/null)"

  if [[ $git_status =~ "Your branch is ahead of" ]]; then
    color="$COLOR_YELLOW"
  elif [[ $git_status =~ "Changes not staged for commit" ]]; then
    color="$COLOR_RED"
  elif [[ $git_status =~ "Untracked files" ]]; then
    color="$COLOR_RED"
  else
    color="$COLOR_GREEN"
  fi

  local on_branch="On branch ([^${IFS}]*)"
  local on_commit="HEAD detached at ([^${IFS}]*)"
  local info
  if [[ $git_status =~ $on_branch ]]; then
    local branch=${BASH_REMATCH[1]}
    info="($branch)"
  elif [[ $git_status =~ $on_commit ]]; then
    local commit=${BASH_REMATCH[1]}
    info="($commit)"
  else 
    info="local"
  fi

  echo -e "${color}${info}"
}

truncate.sh (along with .bash_profile and git-prompt.sh) can be viewed in this gist if desired. If it turns out that it is the culprit, I'll edit the code into the question. But for the sake of brevity and reducing noise I'm leaving it out for now.

Upvotes: 4

Views: 614

Answers (1)

John Kugelman
John Kugelman

Reputation: 361595

Bash is confused about how long your prompts are.

PS1+="\[$COLOR_WHITE\]\$\[$COLOR_RESET\] 

Notice how the colors above are surrounded by \[ and \]? Those markers delimit non-printing characters that don't advance the cursor.

git_prompt is missing them. You'll need to split it into two functions to get it working, one for color and one for info. For example:

PS1="\[\$(git_color)\]\$(git_info)"

Upvotes: 4

Related Questions