第十三章 定制提示符

前言

  1. 本章将会讲解一个看似微不足道的细节:shell 提示符。通过讲解,我们会发现 shell 和终端仿真器程序的内部工作机制。
  2. 和 Linux 中的很多程序一样,shell 提示符的可配置性很高。尽管大多数用户并不重视提示符,但是,一旦我们学会了怎样控制它,它就会成为一种相当有用的设备。

提示符的分解

  1. 基本介绍
  • 系统的默认提示符看起来如下所示。
    1
    [me@linux ~]$
  • 提示符是由名为 PS1 (prompt string 1 的缩写,即提示符字符串 1) 的环境变量定义的。
  • echo 命令可以帮助用户看到 PS1 的值。
    1
    2
    [me@linuxbox ~]$ echo $PS1
    [\u@\h \w]\$
  • 如果输出的结果同本书的范例不同,也不需要担心。每一个 Linux 发行版本对此提示符字符串的定义都会有所不同,有一些甚至定义的很奇怪。
  • PS1 包含了一些提示符中出现的符号,比如方括号、@ 符号和美元符号,但是其余的部分则令人困惑。
  1. shell 提示符中使用的转义字符
转义字符 含义
\a ASCII 铃声。在遇到该转义字符时,计算机发出哔哔声
\d 当前日期,以星期、月、日的形式表示,如 Mon May 26
\h 本地机器的主机名,但是不带域名
\H 完整的主机名
\j 当前 shell 会话中进行的任务个数
\l 当前终端设备的名称
\n 换行符
\r 回车符
\s shell 程序的名称
\t 当前时间 (24小时制) ,格式为小时,分钟,秒
\T 当前时间 (12小时制)
@ 当前时间 (12小时制,格式为 AM/PM)
\A 当前 (24小时制) ,格式为小时:分钟
\u 当前用户的用户名
\v shell 的版本号
\V shell 的版本号和发行号
\w 当前工作目录名
\W 当前工作目录名称的最后一部分
! 当前命令的历史编号
# 当前 shell 会话中输入的命令数
$ 在非管理权限下输出 $ 。在管理员权限下输出 #
\[ 标志一个或多个非打印字符序列的开始。用于嵌入非打印的控制字符,使其以一定方式操纵终端仿真器,比如移动光标或更改文本颜色
\] 标志着非显示字符序列的结束

尝试设计提示符

  1. 通过这个特殊字符列表,我们可以更改提示符来查看效果。我们首先备份现有的字符串,以便过后进行恢复。
  2. 为此,将现有的字符串复制到我们创建的另外一个 shell 变量中。
    1
    [me@linux ~]$ ps1_old="$PS1"
  3. 这样我们就创建了名为 ps1_old 的新变量,并将 PS1 的值赋给了 ps1_old 。我们可以使用 echo 命令来验证 PS1 的值确实已经被复制了。
    1
    2
    [me@linuxbox ~]$ echo $ps_old
    [\u@\h \W]\$
  4. 在终端会话中,用户随时可以通过这个过程的逆操作来复原最初的提示符。
    1
    [me@linuxbox ~]$ PS1='$ps1_old'
  5. 现在一切准备就绪。接下来让我们看看如果提示符为空会发生什么。
    1
    [me@linuxbox ~]$ PS1=
  6. 若提示符为空,那么用户不会得到任何提示。根本就没有提示字符串嘛!尽管提示符就在那里,但是系统并不会显示。这样的提示看起来很令人困惑,所以现在将提示符设置为最简略的内容。
  7. 这样就好多了,至少现在用户知道自己在做什么了。可以注意到双引号中末尾的空格。当显示提示符时,这个空格会把美元符号和光标分隔开。
  8. 在提示符中添加一个铃声。
    1
    $ PS1="\a\$"
  9. 这样以来,每当系统显示提示符的时候,用户都会听到哔哔声。虽然这可能会使用户感到厌烦,但是在一些情况下可能会很有帮助,比如可以在一个耗时特别长的命令执行完毕通知用户。
  10. 接下来,我们试着创建一个信息丰富的提示符,其中包括主机名和当天的时间信息。
    1
    $ PS1="\A \h \$"
  11. 如果我们需要记录某些任务的执行时间,在提示符中添加时间信息会比较有用。最后,我们定制一个类似于最初样式的提示符。
    1
    2
    17:37 linuxbox $ PS1="<\u@\h \W>\$"
    <me@linuxbox ~>$

添加颜色

  1. 基本介绍
  • 大多数终端都会响应某些非打印字符序列,来控制光标位置、字符属性 (如颜色、粗体、文本闪烁等) 内容。
  • 字符颜色是由发送到终端仿真器的一个 ANSI 转移代码来控制的,该转义代码嵌入到了要显示的字符流中。控制代码不会打印到屏幕上,而是被中断解释为一条指令。
  • 在之前的表中可以看到,\[ 和 \] 这两个序列用来封装非打印字符串。一个 ANSI 转义代码以八进制 033 (该代码由转义键 [escape key] 产生开始) ,后面跟着一个可选的字符属性,之后是一条指令。
  • 例如,将文本颜色设置为正常 (attribute=0) 、黑色的代码是\033[0;30m 。
  1. 设置文本颜色的转义序列
字符序列 文本颜色
\033[0;30m 黑色
\033[0;31m 红色
\033[0;32m 绿色
\033[0;33m 棕色
\033[0;34m 蓝色
\033[0;35m 紫色
\033[0;36m 青色
\033[0;37m 淡灰色
\033[1;30m 深灰色
\033[1;31m 淡红色
\033[1;32m 淡绿色
\033[1;33m 黄色
\033[1;34m 淡蓝色
\033[1;35m 淡紫色
\033[1;36m 淡青色
\033[1;37m 白色
  1. 案例一
  • 现在让我们尝试创造红色的提示符 (本书中表现为灰色) 。我们将相应的转义代码插入提示符的开端。
    1
    2
    <me@linuxbox ~>$ PS1 = "\[\033[0;31m\]<\u@\h \W>\$"
    <me@linuxbox ~>
  • 事实证明操作可行,但是此时用户输入的所有文字也变成红色。要修复这个问题,可以在提示符的末尾插入一条转移码,以通知终端仿真器回复到原来的颜色。
    1
    2
    <me@linuxbox ~>$ PS1="\[\033[0;31m\]<\u@\h \W>\$\[\033[0m\"
    <me@linuxbox ~>$
  1. 设置背景颜色的转义序列
字符序列 背景颜色
\033[0;40m 黑色
\033[0;41m 红色
\033[0;42m 绿色
\033[0;43m 棕色
\033[0;44m 蓝色
\033[0;45m 紫色
\033[0;46m 青色
\033[0;47m 淡灰色
  1. 案例二
  • 通过为第一个转义代码做一些修改,就可以创建带有红色背景的提示符。
    1
    <me@linuxbox ~>$ PS1="\[\033[0;41m\]<\u@h \W>\$\[\033[0m\]]"
  • 用户除了正常 (0) 和粗体 (1) 属性外,还可以设置为下划线 (4) 、闪烁 (5) 和斜体 (7) 。

移动光标

  1. 基本介绍
  • 转义代码也可以用来定位光标。比如在提示符出现的时候,这些转义代码通常用来在屏幕的不同位置 (比如屏幕上方的一角) 显示一个时钟或其他信息。
  1. 光标移动转义序列
转义码 动作
\033[1;cH 将光标移动至 1 行 c 列
\033[nA 将光标向上移动 n 行
\033[nB 将光标向下移动 n 行
\033[nC 将光标向前移动 n 个字符
\033[nD 将光标向后移动 n 个字符
\033[2J 清空屏幕并将光标移动至左上角 (第 0 行第 0 列)
\033[K 清空当前光标位置到行末的内容
\033[s 存储当前光标位置
\033[u 恢复之前存储的光标位置
  1. 案例
  • 通过使用这些代码,用户可以构建这样的一条提示符。每当提示符出现时,屏幕的上方会绘制出一个红色的横条,横条中有用黄色文本显示的时间。用于提示符的编码就是一个看起来很可怕的字符串:
    1
    PS1="\[\033[s\033[0;0H\033[0;41m\033[K\033[1;33m\t\033[Om\033[u\]<\u@\h \W>\$"
  1. 复杂提示符的分解
字符序列 动作
\[ 开始一个非打印字符序列。其真正目的是为了让 bash 正确计算可见提示符的长度。如果没有该字符,命令行编辑功能无法正确定位光标
\033[s 存储光标位置。在屏幕的顶部横条绘制完成并显示时间后,读取并使光标返回此位置。需要注意的是,一些终端仿真器不支持该代码
\033[0;0H] 将光标移动至左上角,即第 0 行第 0 列
\033[0;41m] 将背景颜色设置为红色
\033[K 将光标当前位置 (左上角) 到行末的内容清空。因为现在背景颜色已经是红色了,所以清空后的行就是红色,也就会绘出了红色的横条。需要注意的是清空行的内容并不会改变光标的位置,光标仍处于屏幕左上角
\033[1;33m 将文本颜色设置为黄色
\t 显示当前时间。尽管这是一个可打印的元素,但是还是将其包含在提示符非打印部分中,这是因为 bash 在计算可见提示符的长度时,不应当将其计算在内
\033[0m 关闭颜色。对文本和背景均有效
\033[u 恢复之前存储的光标位置
\] 结束非打印的字符序列
<\u@\h \W>$ 提示符字符串

保存提示符

  1. 很显然,用户不会想要每次都输入这样一长串代码,所以就需要将提示符存储在某个地方。将提示符添加到 .bashrc 文件中是一个一劳永逸的解决方法。也就是将以下两行代码添加到文件中。
    1
    2
    PS1="\[\033[s\033[0;0H\033[0;41m\033[K\033[1;33m\t\033[Om\033[u\]<\u@\h \W>\$"
    export PS1

参考文章

  • 转载:Linux 命令行大全