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)的输出,以便标题随每个命令更改。