增强版的 Bash 提示符

1
2011
# 作者: riku / 本文采用CC BY-NC-SA 2.5协议授权,转载请注明本文链接

- 来自 Upsuper 的投稿,原文:  http://blog.upsuper.org/advanced-prompt-string-of-bash/

上周六参加了好久没有参加的的 SHLUG 月聚,恰逢 TualatriX 也带团来上海。自由讨论的时候,我看到 TualatriX 的终端十分色彩斑斓,便询问,他给我们展示了他的 bash 的两个特色功能:1、当上一条命令返回结果不为0时显示返回值并高亮显示提示符;2、自动检测git分支。他说这个在他的博客上都可以找到,今天想起来去找了一下,发现了这篇:史上最强的PS1 | I’m TualatriX,感觉满强大的。

不过,说实话,我觉的这个还不够完美,原因有二:一是我发觉高亮显示的时候那个配色相当不怎么样,二是我本来就讨厌提示符太长,这样一下就更长了……于是我就想起 ghosTM 的 zsh 里面有一些信息是放在右边的,我想把返回值也扔右边去,并且是右边上移一行。此外,由于很少使用 git,所以检测 git 分支的功能也就不需要了~

先放一个最终效果图:

然后直接写出了我的新的 PS1:

PS1='`a=$?;if [ $a -ne 0 ]; then a="  "$a; echo -ne "\[\e[s\e[1A\e[$((COLUMNS-2))G\e[31m\e[1;41m${a:(-3)}\e[u\]\[\e[0m\e[7m\e[2m\]"; fi`\[\e[1;32m\]\u@\h:\[\e[0m\e[1;34m\]\W\[\e[1;34m\]\$ \[\e[0m\]'

非常复杂唉……让我自己再看一次都头晕……

分解这个提示符

上面看到这个 PS1 写的非常之复杂,不过其实拆解开来也没什么了不起的,只不过看起来蛋疼罢了~

这个 PS1 可以分为两个部分,第一个部分是:

`a=$?;if [ $a -ne 0 ]; then a="  "$a; echo -ne "\[\e[s\e[1A\e[$((COLUMNS-2))G\e[31m\e[1;41m${a:(-3)}\e[u\]\[\e[0m\e[7m\e[2m\]"; fi`

第二个部分是:

\[\e[1;32m\]\u@\h:\[\e[0m\e[1;34m\]\W\[\e[1;34m\]\$ \[\e[0m\]

我们先来研究第二部份,这个部分看起来比较简短。其中我们可以看到一个 PS1 里面非常基本的结构:\u@\h:\W\$ ,这个结构在我的电脑里就显示为 upsuper@upsuper-laptop:~$ 大家大概可以猜到里面是什么意思了吧。

这个基本骨架理出来,剩下的是看过去最蛋疼的那堆莫名其妙的符号了~我们看到很多 \e[ 这样的东西,事实上这个叫做 ANSI 控制码,在 Linux 和 Windows 的命令行里面都是通用的,\e 是 Escape 键的键码,\e[ 是一切 ANSI 控制码的开头。首先来到 \e[1;32m 这个控制码,这表示设置这个符号之后的字符为亮绿色,而 \e[0m 则是清除所有格式,这样看有没有一点清晰了呢?更多用法可以参考维基百科条目ANSI escape code

之后还有两个东西不清楚,就是 \[ 和 \],这两个并不是 ANSI 控制码,而是 Bash 提供的转义符。他们的解释说实话我没看太懂,不过我的理解大概就是,夹在 \[ 和 \] 之间的部分 Bash 假定他们的宽度为0,不正确地标注这两个符号会导致 Bash 的换行错误。总之在所有控制符两侧都加上这两个就对了~

第二个部分解决了,下面来看蛋疼的第一部份

`a=$?;if [ $a -ne 0 ]; then a="  "$a; echo -ne "\[\e[s\e[1A\e[$((COLUMNS-2))G\e[31m\e[1;41m${a:(-3)}\e[u\]\[\e[0m\e[7m\e[2m\]"; fi`

很明显,整个结构被一个正引号引起来,表示执行并返回其中的结果。这样我们就可以把这个部分分解开来了:

a=$?
if [ $a -ne 0 ]; then
a=" "$a
echo -ne "\[\e[s\e[1A\e[$((COLUMNS-2))G\e[31m\e[1;41m${a:(-3)}\e[u\]\[\e[0m\e[7m\e[2m\]"
fi

稍微懂点编程就会觉得这也没什么技术含量嘛,其中 $? 就是上一个程序运行的返回值,我们获取并判断他,如果不为零就进行下面的操作。a=” “$a 这句我们待会而再看,先看下面那个 echo -ne 的语句。echo 我们知道是显示字符串,而 -ne 实际上是两个参数 -n 和 -e,-n 表示输出字符串后不输出换行符,-e 表示解析后面的转义符。

最后就剩分析那个打印的东西了。我们发现主要部分其实和上面是一样的,无非就是一些设置格式的事情,我们去掉格式设置,发现主要是这样的:

\e[s\e[1A\e[$((COLUMNS-2))G${a:(-3)}\e[u

这个部分仍然包含许多 ANSI 控制符,第一个是 \e[s,表示保存当前光标位置,与最后一个表示恢复光标位置的控制符 \e[u 遥相呼应,由于我们需要大规模移动光标,所以我们要备份一下位置。然后我们看到 \e[1A,这个控制符表示将光标上移一行。然后之后有一个很复杂的东西 \e[$((COLUMNS-2))G,这个对应的控制符是 \e[*G,表示设置光标到第几列,而 $((COLUMNS-2)) 表示这个列数为当前可显示的最大列数-2。后面有一个 ${a:(-3)},也就是取前面的后三位显示(返回值的范围是0-255)。

现在我们回到前面的 a=” “$a,发现这个的目的其实是和 ${a:(-3)} 对应,让这个部分无论如何保证有三个字符可以出现。事实上最初我并不是这么写的,而是写 $((COLUMNS-${#a}+1)),表示 $a 有多长就显示多长。但这样感觉不美观,就改成了固定3字符长。

到这里也就结束了,然后我们发现,其实看过去很复杂的东西,拆开来还是挺简单的嘛~

作者:riku

Bio: 关注新网络、Web2.0、移动应用;Nexus S/Andorid,iPad,FreeBSD,Ubuntu 用户;伪设计师,好推墙运动。
链接:Blog - Twitter - Facebook - 此作者的更多文章

11 Responses to 增强版的 Bash 提示符

Avatar

Zoom.Quiet

Namoroka 3.6.15pre Namoroka 3.6.15pre Ubuntu 10.04 Ubuntu 10.04

三月 1st, 2011 at 9:42 上午

嗯嗯嗯,这么折腾 Bash 还不如直接用 zsh 呢,
PS,俺用 Hg ,所以,也配置出了类似的效果,
可惜无法简单的复用到所有工作终端中,慢慢的,又回到了原始的...

[Reply]

Firefox 3.6.13 Firefox 3.6.13 Ubuntu 10.10 Ubuntu 10.10

ghosTM55 Reply:

@Zoom.Quiet, 用zsh的飘过

[Reply]

Google Chrome 10.0.648.18 Google Chrome 10.0.648.18 GNU/Linux GNU/Linux

znetor Reply:

@ghosTM55,

看到zsh 感觉确实很强大

[Reply]

Firefox 3.6.13 Firefox 3.6.13 Ubuntu 10.10 Ubuntu 10.10

upsuper Reply:

@ghosTM55, 唔,暂时不想折腾zsh呢,虽然看过去确实不错……等有时间了把zsh并gentoo一起折腾一下~

[Reply]

Google Chrome 9.0.597.98 Google Chrome 9.0.597.98 GNU/Linux GNU/Linux

riku Reply:

@Zoom.Quiet, 通常我都用原始的,也不改 shell :)

[Reply]

Avatar

书痕

Google Chrome 9.0.597.94 Google Chrome 9.0.597.94 GNU/Linux GNU/Linux

三月 1st, 2011 at 10:30 上午

习惯了现在的,估计就算用了彩色的,过过瘾后还会转回基本bash的

[Reply]

Avatar

Ian

Firefox 4.0b12 Firefox 4.0b12 Mac OS X 10.6 Mac OS X 10.6

三月 1st, 2011 at 10:59 上午

定义些color的变量就清爽多了。我的加了git branch和rvm的当前版本:

function prompt
{
local WHITE="\[33[1;37m\]"
local GREEN="\[33[0;32m\]"
local CYAN="\[33[0;36m\]"
local GRAY="\[33[0;37m\]"
local BLUE="\[33[0;34m\]"
local RED="\[33[0;31m\]"
local SCREEN_TITLE="33k33\\\\"
export PS1="${GREEN}\u@\h${RED}\$(git branch 2>/dev/null | sed -n 's/^\* \(.*\)$/ (\1)/p')${GRAY}\$(rvm current 2> /dev/null | sed -n 's/..*/ (&)/p') ${CYAN}\w\[33[0m\]
$ "
}

prompt

[Reply]

Avatar

znetor

Google Chrome 10.0.648.18 Google Chrome 10.0.648.18 GNU/Linux GNU/Linux

三月 1st, 2011 at 11:26 上午

riku 也在场啊 ~ 早知道认识一下嘛

[Reply]

Google Chrome 9.0.597.98 Google Chrome 9.0.597.98 GNU/Linux GNU/Linux

riku Reply:

@znetor, 我没在啊,这篇是 Upsuper 投稿的。

[Reply]

Avatar

stufever

Google Chrome 8.0.552.237 Google Chrome 8.0.552.237 GNU/Linux GNU/Linux

三月 1st, 2011 at 9:43 下午

确实挺复杂的

[Reply]

Avatar

jazzi

Chromium 9.0.597.94 Chromium 9.0.597.94 Ubuntu 10.04 Ubuntu 10.04

三月 2nd, 2011 at 9:17 上午

很棒的修饰,这样区分就很明显了。thanks

[Reply]

Comment Form

top

无觅相关文章插件,快速提升流量