bashrc中PS1设置

Posted by GOOD21 on October 31, 2016

工欲善其事,必先利其器。

1、基础

命令行是每一个Linux开发人员都要用到的东西,一个高效的命令行提示符会减少很多不必要的查看命令,例如centos里的bashrc默认会帮忙配置上user、hostname等信息。但是默认配置好的东西永远满足不了程序猿的需求,所以有了这篇文章。

其实不光有PS1,也有PS2/PS3/PS4(不是游戏机的那个…),想了解也可参考《PS1, PS2, PS3, PS4 和 PROMPT_COMMAND》

这里只研究PS1。

bash中命令行提示符的格式是由PS1来控制的。man一下bash,可以看到The value of this parameter is expanded and used as the primary prompt string.

我们再看一下centos默认的/etc/bashrc文件:

if [[ ${EUID} == 0 ]] ; then #如果是root用户
    PS1='\[\033[01;31m\]\h\[\033[01;34m\] \W \$\[\033[00m\] '
else
    PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
fi

是不是巨崩溃…

但是有了以下的表,你就能看明白了。(此时请自行脑部正则表达式…)

字母 含义
\a ASCII 响铃字符(也可以键入 \007)
\d “Wed Sep 06” 格式的日期
\e ASCII 转义字符(也可以键入 \033)
\h 主机名的第一部分(如 “mybox”)
\H 主机的全称(如 “mybox.mydomain.com”)
\j 在此shell中通过按 ^Z 挂起的进程数
\l 此 shell 的终端设备名(如 “ttyp4”)
\n 换行符
\r 回车符
\s shell 的名称(如 “bash”)
\t 24 小时制时间(如 “23:01:01”)
\T 12 小时制时间(如 “11:01:01”)
\@ 带有 am/pm 的 12 小时制时间
\u 用户名
\v bash 的版本(如 2.04)
\V Bash 版本(包括补丁级别)
\w 当前工作目录(如 “/home/drobbins”)
\W 当前工作目录的“基名 (basename)”(如 “drobbins”)
\! 当前命令在历史缓冲区中的位置
\# 命令编号(只要您键入内容,它就会在每次提示时累加)
\$ 如果您不是超级用户 (root),则插入一个 “$”,如果您是超级用户,则显示一个 “#”
\xxx 插入一个用三位数 xxx(用零代替未使用的数字,如 “\007”),表示的 ASCII 字符
\\ 反斜杠
\[ 这个序列应该出现在不移动光标的字符序列(如颜色转义序列)之前,它使 bash 能够正确计算自动换行。
\] 这个序列应该出现在非打印字符序列之后。

如此,我们能干的事情就多了。

\033是8进制(也就是\e),它就是unix下终端转义符ESC(16进制1A,10进制27),ESC[xm 是unix下改变终端输出颜色的命令。

bash中有其自己的配色方案,格式如下:
\[\e[F;B;Cm\]

其中,\[\]是保证其内的非打印字符不占用行上的任何空间,这样就能使自动换行后的颜色设置正常工作了(之前我的shell出现长命令不能换行的bug,就是缺少了这个中括号);

\e[与m之间的内容表示设置颜色,F是前景色,B是背景色,C是代码,多个颜色用分号隔开。但F、B、C顺序可变,这是因为他们的数值不冲突(大家都习惯将C放在前面)。

如果有\e[0m\e[m,都是通知终端将颜色(前景、背景、加粗)设置重置为默认。

再配上俩表:

前景 背景 颜色
30 40 黑色
31 41 红色
32 42 绿色
33 43 黄色
34 44 蓝色
35 45 紫红色
36 46 青蓝色
37 47 白色
代码 意义
0 OFF
1 高亮显示
4 underline
7 反白显示
8 不可见

2、进阶

命令行光看着赏心悦目也不行,必须要有实际的功能,例如我们现在很多时候开发都在用git,经常要查看所在的是哪个branch,所以我们完全可以把branch名字放在提示符里。

只需要在bashrc里面定义一个获取当前分支名称的方法就可以了。原理就是取.git目录下面的HEAD。

附上代码如下:

#查找当前分支,放在git_branch变量里。
find_git_branch () {
    local dir=. head
    until [ "$dir" -ef / ]; do
        if [ -f "$dir/.git/HEAD" ]; then
        head=$(< "$dir/.git/HEAD")
            if [[ $head = ref:\ refs/heads/* ]]; then
                git_branch=" (${head#*/*/})"
            elif [[ $head != '' ]]; then
                git_branch=" (detached)"
            else
                git_branch=" (unknow)"
            fi
            return
        fi
        dir="../$dir"
    done
    git_branch=''
}
#通过git status命令获取是否有改动
#不建议调用此方法,因为git status会有执行时间,导致每次调用bash shell都会有卡顿。
function find_git_dirty () {
    st=$(git status -s 2>/dev/null | tail -n 1)
    if [[ $st == "" ]]; then
        git_dirty=''
    else
        git_dirty='*'
    fi
}

需要注意的是在PS1调用git_branch前,一定要事先执行find_git_branch方法,这时候就用到了PROMPT_COMMAND(上面有提到过)。

最后附上我的个人配色方案,仅供参考。

PROMPT_COMMAND="find_git_branch; $PROMPT_COMMAND"
if [[ ${EUID} == 0 ]] ; then
    PS1="\[\033[01;31m\]\h\[\033[01;34m\] \W \$\[\033[00m\] "
else
    PS1="\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[01;33m\]\$git_branch\[\033[00m\] "
fi

bashrc-ps1-personal-demo