Bash/Prompt 自定义
Bash 有几个提示符可以自定义,以提高生产力、美观度和“技术宅”分数。
提示符
Bash 有五个可以自定义的提示符字符串
PS0在每个命令之后、任何输出之前显示。PS1是主提示符,在每个命令之前显示,因此它是大多数人自定义的提示符。PS2是次提示符,当命令需要更多输入时(例如多行命令)显示。PS3不太常用。它是 Bash 的select内建命令显示的提示符,用于显示交互式菜单。与其他提示符不同,它不会扩展 Bash 转义序列。通常,您会在使用select的脚本中自定义它,而不是在您的.bashrc中。PS4也不常用。它在调试 bash 脚本时显示,以指示间接层级。第一个字符会重复以指示更深的层级。
所有提示符都是通过将相应变量设置为所需字符串来定制的(通常在 ~/.bashrc 中),例如:
PS2='> '
技术
虽然您可以简单地将提示符设置为一个纯文本字符串,但还有多种技术可以使提示符更具动态性和实用性。
Bash 转义序列
在打印提示符字符串时,Bash 会查找特定的反斜杠转义字符,并将其扩展为特殊字符串。例如,\u 会扩展为当前用户名,\A 会扩展为当前时间。因此,PS1 为 '\A \u $ ' 会显示为 17:35 用户名 $ 。
有关转义序列的完整列表,请参阅 man 手册页 bash(1) § PROMPTING 或 Bash 参考手册。
Terminfo 转义序列
除了 Bash 识别的转义字符外,大多数终端还识别特殊转义序列,这些序列会影响终端本身,而不是打印字符。例如,它们可以更改后续打印字符的颜色、将光标移动到任意位置或清除屏幕。这些转义序列可能有些难以辨认,并且可能因终端而异,因此它们记录在 terminfo 数据库中。要查看您的终端支持哪些功能,请运行:
$ infocmp
功能名称(等号前的部分)可以在 terminfo(5) 中查找,以了解其作用。例如,setaf 会设置之后打印的文本的前景色。要获取功能的转义码,可以使用 tput 命令。例如:
$ tput setaf 2
打印设置前景色为绿色的转义序列。
TERM 值。例如,如果您设置了 xterm 而不是 xterm-256color,tput setaf 将只能使用颜色编号 0-7。要将这些功能实际集成到您的提示符中,您可以使用 Bash 的命令替换和字符串插值。例如:
GREEN="\[$(tput setaf 2)\]"
RESET="\[$(tput sgr0)\]"
PS1="${GREEN}my prompt${RESET}> "
\[ \] 中。这有助于 Bash 忽略不可打印字符,从而正确计算提示符的大小。这种包装在命令替换中无效,在这种情况下,必须使用 原始的 \1 \2。ANSI 转义序列
不幸的是,您的终端 terminfo 数据库中可能缺少有效的 ANSI 转义序列。对于较新功能(如 256 色支持)的转义序列,这种情况尤其普遍。在这种情况下,您不能使用 tput,必须手动输入转义序列。
请参阅 Wikipedia:ANSI escape code 获取转义序列的示例。每个转义序列都以一个字面上的转义字符开头,您可以使用 Bash 的转义序列 \e 输入。例如,\e[48;5;209m 会将背景设置为桃红色(如果您支持 256 色),\e[2;2H 将光标移动到屏幕的左上角附近。
在 Bash 转义序列不受支持的情况下(例如 PS3),您可以使用 Bash 的 printf 内建命令获取字面上的转义字符:
ESC=$(printf "\e") PEACH="$ESC[48;5;209m"
嵌入命令
如果您想将某个命令的输出添加到您的提示符中,您可能会尝试使用命令替换。例如,要将可用内存量添加到您的提示符中,您可以尝试:
PS1="$(awk '/MemFree/{print $2}' /proc/meminfo) prompt > "
53718 prompt > 53718 prompt > 53718 prompt >
但这不起作用;显示的内存量每次都一样!这是因为该命令在 PS1 首次设置时只运行一次,之后再也不会运行。诀窍是简单地阻止替换,方法是转义 $ 或在单引号中定义它——无论哪种方式,它都将在提示符实际显示时进行替换:
PS1="\$(awk '/MemFree/{print \$2}' /proc/meminfo) prompt > "
# or
PS1='$(awk "/MemFree/{print \$2}" /proc/meminfo) prompt > '
为了防止长命令使您的 PS1 变得过大,您可以定义函数:
free_mem()
{
awk '/MemFree/{print $2}' /proc/meminfo
}
PS1='$(free_mem) prompt > '
\[ \] 不适用于包含不可打印字符的包装。您可以使用八进制转义符 \001 和 \002(例如使用 printf 或 echo -e)。PROMPT_COMMAND
如果设置了 PROMPT_COMMAND 变量或数组,它将在 PS1 显示之前立即进行评估。这可以用来实现相当强大的效果。例如,它可以根据某个条件重新分配 PS1,或者在每次运行命令时对 Bash 历史记录执行某些操作。
PROMPT_COMMAND 通常不应直接用于向提示符打印字符。在 PS1 之外打印的字符不会被 Bash 计算,这会导致它错误地放置光标和清除字符。要么使用 PROMPT_COMMAND 来设置 PS1,要么查看 嵌入命令。命令输入和输出之间的转义
您可以通过不在 PS1 的末尾重置文本属性来影响 Bash 中的输入文本。例如,在 PS1 的末尾插入 tput blink 会使您键入的命令闪烁。但是,这种效果也会继续到命令的输出,因为当您按下 Enter 键时文本属性不会被重置。
为了在输入命令后、输出显示之前插入转义序列,您可以设置 PS0。或者,您可以捕获 Bash 的 DEBUG 信号,该信号在每个命令执行之前发送:
$ trap 'tput sgr0' DEBUG
自定义 root 提示符
为了确保您知道何时以 root 身份运行,您可以自定义您的 root 提示符,使其明显突出(例如,闪烁的红色?)。这是通过像平常一样自定义 Bash 提示符来完成的,但要在 root 的主目录 /root 中。首先将骨架文件 /etc/skel/.bash_profile 和 /etc/skel/.bashrc 复制到 /root,然后根据需要编辑 /root/.bashrc。
示例
颜色
infocmp 显示 tput 可用的颜色数量,例如 colors#8。要查看您的终端支持的全部颜色范围,您可以使用一个简单的 tput 循环(将 setab 改为 setaf 用于文本前景):
for C in {0..255}; do
tput setab $C
echo -n "$C "
done
tput sgr0
echo
如果这不起作用(并且您无法通过设置 正确的 TERM 值来修复它),您可以测试不同的手动转义序列:
# standard colors
for C in {40..47}; do
echo -en "\e[${C}m$C "
done
# high intensity colors
for C in {100..107}; do
echo -en "\e[${C}m$C "
done
# 256 colors
for C in {16..255}; do
echo -en "\e[48;5;${C}m$C "
done
echo -e "\e(B\e[m"
要将手动转义从背景更改为前景,标准颜色范围是 30..37,高强度范围是 90..97,48 应该改为 38 以表示 256 色。
常用功能
以下 terminfo 功能对于提示符自定义很有用,并且被许多终端支持。#1 和 #2 是数字参数的占位符。
| 功能 | 转义序列 | 描述 |
|---|---|---|
| 文本属性 | ||
| blink | \e[5m | 闪烁文本开 |
| 加粗 | \e[1m | 粗体文本开 |
| dim | \e[2m | 暗淡文本开 |
| rev | \e[7m | 反转视频开(切换文本/背景颜色) |
| sitm | \e[3m | 斜体文本开 |
| ritm | \e[23m | 斜体文本关 |
| smso | \e[7m | 高亮文本开 |
| rmso | \e[27m | 高亮文本关 |
| smul | \e[4m | 下划线文本开 |
| rmul | \e[24m | 下划线文本关 |
| setab #1 | \e[4#1m | 设置背景颜色 #1 (0-7) |
| setaf #1 | \e[3#1m | 设置文本颜色 #1 (0-7) |
| sgr0 | \e(B\e[m | 重置文本属性 |
| 光标移动 | ||
| sc | \e7 | 保存光标位置 |
| rc | \e8 | 恢复保存的光标位置 |
| clear | \e[H\e[2J | 清屏并将光标移至左上角 |
| cuu #1 | \e[#1A | 光标向上移动 #1 行 |
| cud #1 | \e[#1B | 光标向下移动 #1 行 |
| cuf #1 | \e[#1C | 光标向右移动 #1 列 |
| cub #1 | \e[#1D | 光标向左移动 #1 列 |
| home | \e[H | 将光标移至左上角 |
| hpa #1 | \e[#1G | 将光标移至第 #1 列 |
| vpa #1 | \e[#1d | 将光标移至第 #1 行,第一列 |
| cup #1 #2 | \e[#1;#2H | 将光标移至第 #1 行,第 #2 列 |
| 删除字符 | ||
| dch #1 | \e#1P | 删除 #1 个字符(类似于退格) |
| dl #1 | \e#1M | 删除 #1 行 |
| ech #1 | \e#1X | 清空 #1 个字符(不移动光标) |
| ed | \eE[J | 清除屏幕至底部 |
| el | \e[K | 清除行末尾 |
| el1 | \e[1K | 清除行开头 |
可视化退出码
使用与 嵌入命令 相同的技巧,您可以延迟特殊 Bash 变量(如 $?)的插值。因此,以下提示符显示前一个命令的退出代码:
PS1="\$? > " # or PS1='$? > '
0 > false
1 >
使用条件语句和函数可以使这变得更有趣:
exitstatus()
{
if [[ $? == 0 ]]; then
echo ':)'
else
echo 'D:'
fi
}
PS1='$(exitstatus) > '
:) > false
D: >
定位光标
可以在 PS1 内部移动屏幕上的光标,使提示符的不同部分出现在不同位置。但是,为了确保 Bash 正确地定位光标和输出,您必须在完成其他位置的打印后将光标移回原始位置。这可以通过 tput 的 sc 和 rc 功能来保存和恢复光标位置来实现。移动光标的提示符的通用模式是:
PS1="\[$(tput sc; cursor-moving code) positioned prompt stuff $(tput rc)\] normal prompt stuff"
其中整个重新定位的提示符块被包装在 \[ \] 中,以防止 Bash 将其计算为常规提示符的一部分。
右对齐文本
在屏幕右侧打印文本的最简单方法是使用 printf:
rightprompt()
{
printf "%*s" $COLUMNS "right prompt"
}
PS1='\[$(tput sc; rightprompt; tput rc)\]left prompt > '
这会创建一个右对齐的、大小可变的字段 %*s,并将其大小设置为终端的当前列数 $COLUMNS。
任意定位
cup 功能可以将光标移动到屏幕上的特定位置,例如 tput cup 20 5 将光标移动到第 20 行、第 5 列(其中 0 0 是左上角)。cuu、cud、cuf 和 cub(上、下、前、后)会根据当前位置移动光标。例如 tput cuf 10 会将光标向右移动 10 个字符。您可以使用 LINES 和 COLUMNS 变量作为参数来相对于底部和右边缘移动光标。例如,要从右下角向左移动 10 行,向左移动 5 列:
$ tput cup $((LINES - 11)) $((COLUMNS - 6))
自定义终端窗口标题
终端窗口标题的自定义方式与提示符非常相似:通过在 shell 中打印转义序列。因此,用户通常会将窗口标题自定义包含在他们的提示符中。虽然这在技术上是 xterm 的一项功能,但许多现代终端都支持它。使用的转义序列是 ESC]2;新标题BEL,其中 ESC 和 BEL 是转义符和响铃字符。使用 Bash 转义序列,在提示符中更改标题如下所示:
PS1='\[\e]2;new title\a\]prompt > '
当然,您的窗口标题字符串可以包含 嵌入命令 的输出或变量,例如 $PWD,这样标题就会随着每个命令而改变。
参见
- 论坛帖子中的社区示例和截图: 你的 PS1 是什么?(仅登录后可访问)
- Gentoo 的 /etc/bash/bashrc[死链接 2025-11-16—HTTP 404]。另请参阅 gentoo-color-bashAUR。
- tput(1)
- Bash 提示符 HOWTO
- Giles Orr 的示例提示符集合
- Bash 技巧:颜色和格式
- Liquid Prompt — Bash & zsh 的有用自适应提示符
- Bash POWER PROMPT
- Wikipedia:ANSI escape code
- GNU Bash 手册:控制提示符