1. 解剖一个提示符
默认的提示符看起来像这样:
[suli@linuxbox ~]$
注意它包含用户名,主机名和当前工作目录,但是它又是怎样得到这些东西的呢?提示符是由一个环境变量定义的,叫做PS1(是“prompt string one”的简写)。可以通过 echo 命令来查看 PS1 的内容
[suli@linuxbox ~]$ echo $PS1
[\u@\h \W]\$
注意:如果你 shell 提示符的内容和上例不是一模一样,也不必担心。每个 Linux 发行版定义的提示符稍微有点不同,其中一些相当异于寻常
输出结果中,那个
PS1
环境变量包含一些这样的字符,比方说中括号,@ 符号,和美元符号
,但是剩余部分就是个谜。一些机敏的人会把这些看作是由反斜杠转义的特殊字符。这里是一部分字符列表,在提示符中 shell 会特殊对待这些字符:
序列 显示值
\a 以 ASCII 格式编码的铃声. 当遇到这个转义序列时,计算机
会发出嗡嗡的响声
\d 以日,月,天格式来表示当前日期。例如,“Mon May 26.”
\h 本地机的主机名,但不带末尾的域名
\H 完整的主机名
\j 运行在当前 shell 会话中的工作数
\l 当前终端设备名
\n 一个换行符
\r 一个回车符
\s shell 程序名
\t 以 24 小时制,hours:minutes:seconds 的格式表示当前时间
\T 以 12 小时制表示当前时间
\@ 以 12 小时制,AM/PM 格式来表示当前时间
\A 以 24 小时制,hours:minutes 格式表示当前时间
\u 当前用户名
\v shell 程序的版本号
\V Version and release numbers of the shell.
\w 当前工作目录名
\W 当前工作目录名的最后部分
\! 当前命令的历史号
\# 当前 shell 会话中的命令数
\$ 这会显示一个”$” 字符,除非你拥有超级用户权限。在那种
情况下,它会显示一个”#” 字符
\[ 标志着一系列一个或多个非打印字符的开始。这被用来嵌
入非打印的控制字符,这些字符以某种方式来操作终端仿真
器,比方说移动光标或者是更改文本颜色
\] 标志着非打印字符序列结束
2 .试试一些可替代的提示符设计
参照这个特殊字符列表,可以更改提示符来看一下效果。首先把原来提示符字符串的内容备份一下,以备之后恢复原貌。把已有的字符串复制到另一个自己创造的 shell 变量中
[suli@linuxbox ~]$ ps1_old="$PS1"
新创建了一个叫做
ps1_old
的变量,并把变量PS1
的值赋ps1_old
。通过echo
命令可 以证明我们的确复制了PS1
的值
[suli@linuxbox ~]$ echo $ps1_old
[\u@\h \W]\$
在终端会话中,复原提示符只要反向操作就可以了
[suli@linuxbox ~]$ PS1="$ps1_old"
看看如果有一个空的字符串会发生什么:
[suli@linuxbox ~]$ PS1=
如果没有给提示字符串赋值,那么什么也得不到。没有提示字符串,提示符仍然在那里,但是什么也不显示,用一个最小的提示符来代替它:
PS1="\$ "
注意双引号中末尾的空格。当提示符显示的时候,这个空格把美元符号和光标分离开。在提示符中添加一个响铃:
$ PS1="\a\$ "
现在每次提示符显示的时候,我们应该能听到嗡嗡声。这会变得很烦人,但是它可能会很有用,特别是当一个需要运行很长时间的命令执行完后,我们要得到通知。 下一步,让我们试着创建一个信息丰富的提示符,包含主机名和当天时间的信息
$ PS1="\A \h \$ "
17:33 linuxbox $
3. 添加颜色
大多数终端仿真器程序支持一定的非打印字符序列来控制,比方说字符属性(像颜色,黑体和闪烁)和光标位置。 Unix 和类Unix 的系统有两个相当复杂的子系统来处理终端控制领域的混乱局面(称为 termcap 和 terminfo)。如果查看一下终端仿真器最底层的属性设置,可能会找到一个关于终端仿真器类型的设置
为了使所有的终端都讲某种通用语言,美国国家标准委员会(ANSI)制定了一套标准的字符序列集合来控制视频终端。原先 DOS 用户会记得
ANSI.SYS
文件,这是一个用来使这些编码解释生效的文件。 字符颜色是由发送到终端仿真器的一个嵌入到了要显示的字符流中的 ANSI转义编码来控制的。这个控制编码不会“打印”到屏幕上,而是被终端解释为一个指令。正如在上表看到的字符序列,这个 [ 和]序列被用来封装这些非打印字符。一个 ANSI 转义编码以一个八进制 033(这个编码是由退出按键产生的)开头,其后跟着一个可选的字符属性,在之后是一个指令。例如,把文本颜色设为正常(attribute = 0),黑色文本的编码如下:
\033[0;30m
这里是一个可用的文本颜色列表。注意这些颜色被分为两组,由应用程序粗体字符属性(1)分化开来,这个属性可以描绘出“浅”色文本
序列 文本颜色 序列 文本颜色
\033[0;30m 黑色 \033[1;30m 深灰色
\033[0;31m 红色 \033[1;31m 浅红色
\033[0;32m 绿色 \033[1;32m 浅绿色
\033[0;33m 棕色 \033[1;33m 黄色
\033[0;34m 蓝色 \033[1;34m 浅蓝色
\033[0;35m 粉红 \033[1;35m 浅粉色
\033[0;36m 青色 \033[1;36m 浅青色
\033[0;37m 浅灰色 \033[1;37m 白色
试着制作一个红色提示符。在开头加入转义编码:
[suli@linuxbox ~]$ PS1='\[\033[0;31m\]<\u@\h \W>\$'
<suli@linuxbox ~>$
提示符生效了,但是注意在提示符之后输入的文本也是红色的。为了修改这个问题,添加另一个转义编码到这个提示符的末尾来告诉终端仿真器恢复到原来的颜色。
<suli@linuxbox ~>$ PS1='\[\033[0;31m\]<\u@\h \W>\$\[\033[0m\]'
<suli@linuxbox ~>$
也有可能要设置文本的背景颜色,使用下面列出的转义编码。这个背景颜色不支持黑体属性
\033[0;40m 蓝色 \033[1;44m 黑色
\033[0;41m 红色 \033[1;45m 紫色
\033[0;42m 绿色 \033[1;46m 青色
\033[0;43m 棕色 \033[1;47m 浅灰色
我们可以创建一个带有红色背景的提示符,只是对第一个转义编码做个简单的修改
<suli@linuxbox ~>$ PS1='\[\033[0;41m\]<\u@\h \W>\$\[\033[0m\] '
<suli@linuxbox ~>$
注意:除了正常的 (0) 和黑体 (1) 字符属性之外,文本也可以具有下划线 (4),闪烁 (5),和 反向 (7)属性
4 .移动光标
转义编码也可以用来定位光标。这些编码被普遍地用来,每次当提示符出现的时候,会在屏幕的不同位置比如说上面一个角落,显示一个时钟或者其它一些信息。这里是一系列用来定位光 标的转义编码
转义编码 行动
\033[l;cH 把光标移到第 l 行,第 c 列
\033[nA 把光标向上移动 n 行
\033[nB 把光标向下移动 n 行
\033[nC 把光标向前移动 n 个字符
\033[nD 把光标向后移动 n 个字符
\033[2J 清空屏幕,把光标移到左上角(第零行,第零列)
\033[K 清空从光标位置到当前行末的内容
\033[s 存储当前光标位置
\033[u 唤醒之前存储的光标位置
使用上面的编码将构建一个提示符,每次当这个提示符出现的时候,会在屏幕的上方画出一个包含时钟(由黄色文本渲染)的红色长条。构建好的提示符的编码就是这串看起来令人敬畏的字符串:
PS1='\[\033[s\033[0;0H\033[0;41m\033[K\033[1;33m\t\033[0m\033[u\]
<\u@\h \W>\$ '
让我们分别看一下这个字符串的每一部分所表示的意思:
序列 行动
\[ 开始一个非打印字符序列。其真正的目的是为了让 bash 能
够正确地计算提示符的大小。如果没有这个转义字符的话,
命令行编辑功能会弄错光标的位置
\033[s 存储光标位置。这个用来使光标能回到原来提示符的位置,
当长条和时钟显示到屏幕上方之后。当心一些终端仿真器
不推崇这个编码
\033[0;0H 把光标移到屏幕左上角,也就是第零行,第零列的位置
\033[0;41m 把背景设置为红色
\033[K 清空从当前光标位置到行末的内容。因为现在背景颜色是
红色,则被清空行背景成为红色,以此来创建长条。注意虽
然一直清空到行末,但是不改变光标位置,它仍然在屏幕左
上角
\033[1;33m 把文本颜色设为黄色
\t 显示当前时间。虽然这是一个可“打印”的元素,但我们仍
把它包含在提示符的非打印部分,因为我们不想 bash 在计
算可见提示符的真正大小时包括这个时钟在内
\033[0m 关闭颜色设置。这对文本和背景都起作用
\033[u 恢复到之前保存过的光标位置处
\] 结束非打印字符序列
<\u@\h \W>\$ 提示符字符串
5. 保存提示符
把这个提示符存储在某个地方。通过把它添加到
.bashrc
文件,可以使这个提示符永久存在。为了达到目的,把下面这两行添加到.bashrc
文件中
PS1='\[\033[s\033[0;0H\033[0;41m\033[K\033[1;33m\t\033[0m\033[u\]<\u@\h \W>\$ '
export PS1