Bash/提示符自定义
Bash 有几个提示符可以自定义,以提高生产力、美观性和极客信誉。
提示符
Bash 有五个可以自定义的提示字符串
PS0
在每个命令之后,任何输出之前显示。PS1
是主提示符,在每个命令之前显示,因此它是大多数人自定义的提示符。PS2
是当命令需要更多输入时(例如,多行命令)显示的辅助提示符。PS3
不常用。它是为 Bash 的select
内置命令显示的提示符,用于显示交互式菜单。与其他提示符不同,它不展开 Bash 转义序列。通常,您会在使用select
的脚本中自定义它,而不是在.bashrc
中。PS4
也不常用。它在调试 bash 脚本以指示间接级别时显示。第一个字符重复以指示更深的级别。
所有提示符都是通过将相应的变量设置为所需的字符串(通常在 ~/.bashrc
中)来自定义的,例如
PS2='> '
技巧
虽然可以简单地将提示符设置为纯字符串,但有多种技巧可以使提示符更动态和有用。
Bash 转义序列
打印提示字符串时,Bash 会查找某些反斜杠转义字符,并将它们展开为特殊字符串。例如,\u
展开为当前用户名,\A
展开为当前时间。因此,'\A \u $ '
的 PS1 将打印为 17:35 username $
。
有关转义序列的完整列表,请参阅手册页 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 转义码。每个转义序列都以文字转义字符开头,您可以使用 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
,对于 256 色,48 应更改为 38。
常用功能
以下 terminfo 功能 对于提示符自定义非常有用,并且受到许多终端的支持。#1 和 #2 是数值参数的占位符。
功能 | 转义序列 | 描述 |
---|---|---|
文本属性 | ||
blink | \e[5m | 闪烁文本开启 |
bold | \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
)的输出,以便标题随每个命令更改。