损坏的Bash提示符换行问题

3
我正在OsX上自定义我的bash提示符,以包括git分支和一些分支状态标记。这会破坏换行。
我知道我必须添加 \[ 和 \] 来防止这个问题,但在函数中这样做会显示文字 \[ 和 \]。
我该怎么在这些函数中转义这样的序列?
免责声明:这是我在bash脚本编写方面的首次尝试。
function parse_git_dirty {
  # TODO make git status response a variable
  # [branch+] : working dir has staged changes
  if [[ $(git status 2> /dev/null | grep "to be committed") ]]
  then S=$S"$(tput setaf 2)+$(tput sgr0)"
  fi
  # [branch+] : working dir has unstaged changes
  if [[ $(git status 2> /dev/null | grep "not staged for commit") ]]
  then S=$S"$(tput setaf 1)+$(tput sgr0)"
  fi
  # [branch+] : working dir has untracked files
  if [[ $(git status 2> /dev/null | grep "tracked files") ]]
  then S=$S"$(tput setaf 1)+$(tput sgr0)"
  fi
  # [branch<] : local branch is behind origin
  if [[ $(git status 2> /dev/null | grep "Your branch is behind") ]]
  then S=$S"$(tput setaf 5)<$(tput sgr0)"
  fi
  # [branch>] : local branch is ahead origin
  if [[ $(git status 2> /dev/null | grep "branch is ahead of") ]]
  then S=$S"$(tput setaf 5)>$(tput sgr0)"
  fi
  # [branch<>] : branches have diverged
  if [[ $(git status 2> /dev/null | grep "have diverged") ]]
  then S=$S"$(tput setaf 5)<>$(tput sgr0)"
  fi
  echo $S
}
function parse_git_branch {
  git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
}
function show_git_branch {
  if [[ $(parse_git_branch) ]]
  then echo "$(tput setaf 2)($(tput sgr0)$(parse_git_branch)$(parse_git_dirty)$(tput setaf 2))$(tput sgr0)"
  fi
}
export PS1="\u\[$(tput setaf 2)\]@\[$(tput sgr0)\]\h\[$(tput setaf 2)\]:\[$(tput sgr0)\]\W\[\$(show_git_branch)\] "

不确定问题出在哪里,您的代码似乎可以正常工作,使用它我得到了以下提示:hutcho@hutcho-M17x:math(master+)。顺便说一句,这是一个很酷的想法。 - luke h
我有一些(并不是很罕见的)存储库,其中git status需要大约40秒才能完成,而您的代码将为每个bash提示符运行6次git status!我在下面添加了一个答案,提到了__git_ps1,它可能做你想要的事情,并且可以配置输出的不同详细级别。 - Mark Longair
3个回答

5

很高兴听到你已经解决了版本的问题,但我认为值得指出的是,git已经内置了一个有用且经过精心设计的bash函数,称为__git_ps1,您可以将其包含在您的PS1中。例如,您可以像这样使用它:

 export PS1='blah blah blah$(__git_ps1 " (%s)") '

如果您不在git存储库中,$(__git_ps1 " (%s)")将变为空字符串。但是,如果您在存储库中,格式字符串将被使用。这通常会显示当前分支,但如果您处于合并或rebase的中间,则会显示该信息。
默认情况下,__git_ps1不会显示树是否脏或存在未跟踪的文件,因为在某些存储库中,这可能会使您的bash提示出现得非常慢。但是,如果您也想查看此信息,它将显示它们,如果您将GIT_PS1_SHOWDIRTYSTATEGIT_PS1_SHOWUNTRACKEDFILES设置为非空值。
您可以在git-completion.sh源文件的顶部找到更多信息。

有趣的是,我重新发明了轮子,并且在脏状态和本地与远程状态方面几乎得到了与__git_ps1相同的标记。 - Benoît Pointet

3

在赋值语句中,需要使用单引号将值括起来:

export PS1='\u\[$(tput setaf 2)\]@\[$(tput sgr0)\]\h\[$(tput setaf 2)\]:\[$(tput sgr0)\]\W\[$(show_git_branch)\] '

由于在发出提示时评估内容,因此您不需要像其他情况下那样使用双引号。


谢谢!我只需要移除 show_git_branch 函数的转义,就可以正常工作了。 - Benoît Pointet
@BenoîtPointet:抱歉我错过了那个。我已经纠正了我的答案。 - Dennis Williamson

1

感谢 Dennis,修正后的代码如下:

function parse_git_dirty {
  # TODO make git status response a variable
  # [branch+] : working dir has staged changes
  if [[ $(git status 2> /dev/null | grep "to be committed") ]]
  then S=$S"$(tput setaf 2)+$(tput sgr0)"
  fi
  # [branch+] : working dir has unstaged changes
  if [[ $(git status 2> /dev/null | grep "not staged for commit") ]]
  then S=$S"$(tput setaf 1)+$(tput sgr0)"
  fi
  # [branch+] : working dir has untracked files
  if [[ $(git status 2> /dev/null | grep "tracked files") ]]
  then S=$S"$(tput setaf 1)+$(tput sgr0)"
  fi
  # [branch<] : local branch is behind origin
  if [[ $(git status 2> /dev/null | grep "Your branch is behind") ]]
  then S=$S"$(tput setaf 5)<$(tput sgr0)"
  fi
  # [branch>] : local branch is ahead origin
  if [[ $(git status 2> /dev/null | grep "branch is ahead of") ]]
  then S=$S"$(tput setaf 5)>$(tput sgr0)"
  fi
  # [branch<>] : branches have diverged
  if [[ $(git status 2> /dev/null | grep "have diverged") ]]
  then S=$S"$(tput setaf 5)<>$(tput sgr0)"
  fi
  echo $S
}
function parse_git_branch {
  git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
}
function show_git_branch {
  if [[ $(parse_git_branch) ]]
  then echo "$(tput setaf 2)($(tput sgr0)$(parse_git_branch)$(parse_git_dirty)$(tput setaf 2))$(tput sgr0)"
  fi
}
export PS1='\u\[$(tput setaf 2)\]@\[$(tput sgr0)\]\h\[$(tput setaf 2)\]:\[$(tput sgr0)\]\W\[$(show_git_branch)\] '

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接