本篇文章介绍如何在代码中应用 ANSI 本义码来设置终端的字符显示色彩、挪动光标地位等,并实现一个进度条百分比跳变的成果。
ANSI 本义码
在 Linux 中,能够应用 ANSI 本义码(ANSI escape codes)设置终端的字符显示色彩、挪动光标地位、革除字符显示等。
ANSI 本义码是由终端本身反对,独立于编程语言之外,能够在 C 语言、Java、Python、或者 Shell 中应用。
上面以 bash shell 为例来阐明如何应用 ANSI 本义码。
ANSI 本义码格局
ANSI 本义码由一串 ASCII 编码的字符串组成,要求以 ASCII 编码的 Escape 字符和 [ 字符结尾,前面跟着具体的本义码,指定相应的操作。根本格局如下:
Esc[escape code
Escape 字符也就是 Esc 键对应的字符。
因为按 Esc 键,不会失去一个可显示的字符,须要用具体的编码值来示意这个字符。
在不同编程语言中,示意字符编码值的写法可能不一样。个别罕用 \e
转义字符来示意 Esc 字符。
应用 echo 命令测试 ANSI 本义码
在 bash shell 中,能够应用 echo
命令的 -e
选项来测试 ANSI 本义码。
查看 man echo 对 -e
选项阐明如下:
-e
enable interpretation of backslash escapes.
If -e is in effect, the following sequences are recognized:
e
escape
0NNN
byte with octal value NNN (1 to 3 digits).
即,在 echo
命令中,-e
选项能够指定解决转义字符。
\e
转义字符示意 escape 字符。
\0NNN
转义字符应用八进制来获取 NNN 编码值对应的字符。
在 ASCII 编码中,Escape 字符对应的八进制值是 033。
则在 echo
命令中,\033
示意 escape 字符。
应用 echo
命令测试 ANSI 本义码时,能够写为 echo -e "\033[31m"
。
这里的 31m 本义码示意要把终端字符的前景色设成红色。
Linux 的 printf 命令也能够输入 ANSI 本义码,而且不须要加 -e
选项,例如写为 `printf “e[31m”。
留神 :这里须要用双引号、或者单引号把 033[31m 括起来,防止 bash 本身对 \
进行本义,会去掉 \
字符,导致 echo
命令收不到 \
字符,无奈解决转义字符。
也能够写为 echo -e "\e[31m"
,\e
也示意 escape 字符。
前面测试的时候,对立应用 \e
的模式,少输出一些字符。
具体测试如下:
$ echo -e “e[31m”
<span style=”color:red;”>$ echo -e “e[0m”</span>
$
执行 echo -e "\e[31m"
命令后,终端的提醒字符会变成红色,之后输出的字符也都会变成红色。
即,终端的默认字符色彩变成了红色。
执行 echo -e "\e[0m"
命令重置终端属性,让终端的字符色彩变成原来的默认色彩。
这里的 0m 本义码示意重置字符显示属性。
一般来说,为了不影响终端本身的显示,应用 ANSI 本义码设置某个字符串的显示色彩后,倡议随后应用 0m 本义码来重置为原来的色彩。
举例说明如下:
$ echo -e “e[31mThis is a red string.e[0m”
<span style=”color:red;”>This is a red string.</span>
$
在下面命令中,\e[31m
是一个 ANSI 本义码,示意设置终端字符色彩为红色。
\e[0m
也是一个 ANSI 本义码,示意重置终端的色彩属性,会复原成原来的色彩。
在这两个本义码两头的字符串会显示在终端上。
执行该命令后,终端的提示符会显示为原来的色彩。
设置终端字符色彩的 ANSI 本义码
上面具体阐明设置终端字符色彩的 ANSI 本义码,其根本格局如下:
Esc[Value;...;Valuem
这里的 Value 能够提供多个值,不同值之间用分号‘;’隔开。
这些值能够别离指定字符的前景色、背景色、字符属性(粗体、下划线、反转)。它们之间的程序不限。
本义码最初以 m
字符结尾。
设置字符前景色的值如下:
色彩值 | 色彩 |
---|---|
30 | 彩色 |
31 | 红色 |
32 | 绿色 |
33 | 黄色 |
34 | 蓝色 |
35 | 紫色 |
36 | 青色 |
37 | 红色 |
设置字符背景色的值如下:
色彩值 | 色彩 |
---|---|
40 | 彩色 |
41 | 红色 |
42 | 绿色 |
43 | 黄色 |
44 | 蓝色 |
45 | 紫色 |
46 | 青色 |
47 | 红色 |
设置字符属性的值如下:
属性值 | 属性含意 |
---|---|
0 | 重置所有属性,蕴含字符色彩 |
1 | 设成粗体 |
4 | 增加下划线 |
5 | 关上闪动 |
7 | 色彩反转 |
8 | 显示不可见的文本 |
具体举例如下:
$ echo -e “e[31;44mFg color: Red. Bg color: Blue.e[0m”
<span style=”color:red;background-color:blue;”>Fg color: Red. Bg color: Blue.</span>
$ echo -e “e[44;31mFg color: Red. Bg color: Blue.e[0m”
<span style=”color:red;background-color:blue;”>Fg color: Red. Bg color: Blue.</span>
能够看到,\e[31;44m
、\e[44;31m
这两个本义码设置的字符色彩成果是一样的。
所给的前景色、背景色没有要求先后顺序。
目前的大部分终端都反对 256 色,能够应用 Esc[38;5;Valuem
来设置终端字符为 256 色。
这里的 Value 取值是 0-255。
例如,echo -e "\e[38;5;111mAAAAAA\e[0m"
命令设置为 111 对应的色彩。
具体的色彩取值能够查看 256 色的色彩表。网上的很多文章都有阐明。这里不再列举。
应用 ANSI 本义码挪动终端光标
ANSI 本义码能够用来挪动终端的光标地位,从而扭转字符的输入地位。
具体举例如下:
$ echo -e "123456789\e[4Dabc"
12345abc9
在这个命令中,\e[4D
本义码示意把光标往左挪动 4 列。
能够看到,光标挪动 4 列后,位于字符 6 所在的地位,从新输入 abc,笼罩了原来的 678 三个字符。
挪动光标的具体本义码阐明如下:
本义码 | 含意 |
---|---|
Esc[nA | 光标上移 n 行,列数不变。挪动到终端最上边后不再挪动 |
Esc[nB | 光标下移 n 行,列数不变。挪动到终端最下边后不再挪动 |
Esc[nC | 光标右移 n 列,行数不变。挪动到终端最左边后不再挪动 |
Esc[nD | 光标左移 n 列,行数不变。挪动到终端最右边后不再挪动 |
Esc[nE | 光标下移 n 行,列数变到行首 |
Esc[nF | 光标上移 n 行,列数变到行首 |
Esc[Line;ColumnH | 把光标挪动到指定的行数和列数。如果不提供值,默认值为 0 |
Esc[ColumnG | 把光标挪动到第 Column 列,以后行数放弃不变 |
Esc[s | 保留以后光标地位,后续能够用 Esc[u 跳到保留的地位 |
Esc[u | 跳转到 Esc[s 所保留的光标地位 |
Esc[?25l | 暗藏光标(在 25 前面是小写字母 l) |
Esc[?25h | 显示光标 |
下面所说的终端地位指的是终端可见的窗口地位,不包含缓冲区地位。
即,窗口显示不会产生滚动,只在以后可见的窗口区域跳转光标。
留神 :因为 echo
命令默认会输入换行符,导致挪动光标后再次换行,会对光标挪动成果造成烦扰。
在测试挪动光标的本义码时,倡议用 printf
命令测试。该命令默认不会输入换行符。
因为 bash 外面须要按下回车才执行命令,会影响光标的左右挪动成果,倡议在 printf
本身输入的内容中左右挪动光标。
理论测试发现,光标右移 n 列,光标会位于第 n 列的前面,之后输入的字符串会从 n+1 列开始。
Esc[C、Esc[0C、和 Esc[1C 的成果雷同,都是光标右移 1 列。
相似的,Esc[D、Esc[0D、和 Esc[1D 的成果雷同,都是光标左移 1 列。
应用 printf
命令测试如下:
$ printf "123456789\e[1Da\n"
12345678a
$ printf "123456789\e[0Da\n"
12345678a
$ printf "123456789\e[Da\n"
12345678a
能够看到,应用 \e[D
、\e[0D
、\e[1D
往左挪动光标,而后输入字符 a,都是笼罩同一个字符 9。
这三个本义码的光标挪动成果雷同。
$ printf "123456789\e[4Da\n"
12345a789
$ printf "123456789\e[4D\e[Ca\n"
123456a89
$ printf "123456789\e[4D\e[0Ca\n"
123456a89
$ printf "123456789\e[4D\e[1Ca\n"
123456a89
\e[4D
把光标左移 4 列,挪动到字符 6 的地位。
\e[C
、\e[0C
、\e[1C
都是往右挪动光标到下一列,到字符 7 的地位,输入字符 a,笼罩了字符 7。
通过挪动光标实现进度百分比的成果
咱们能够通过挪动光标实现进度百分比的成果。假如有一个 progress.sh
脚本,内容如下:
#!/bin/bash
for ((i = 0; i <= 100; ++i)); do
printf "\e[5D%3d%%" $i
sleep 0.1s
done
echo
这里应用 printf
命令进行输入,以便格式化字符串。
printf
命令也是应用 \e
来示意 escape 字符。
\e[5D
本义码示意把光标左移 5 列。
因为所输入的字符不超过 5 个字符,每次光标左移 5 列,都会挪动到最右边,从第一列开始输入。
那么前面输入的内容会笼罩后面输入的内容,达到在同一行反复输入的成果。
sleep 0.1s
命令示意暂停 0.1 秒。增加这个语句,以便分明地看到进度百分比跳变。否则执行过快,百分比很快就跳到 100%。
执行 progress.sh
脚本的后果如下:
$ ./progress.sh
100%
这里不是动图,看不到进度百分比跳变。理论执行就能看到。
从后果来看,在 for 循环中屡次打印信息,这些信息都打印在同一行,并笼罩后面的输入。而不是换行打印。
通过挪动光标实现进度条的成果
上面通过挪动光标实现进度条的成果。假如有一个 progressbar.sh
脚本,内容如下:
#!/bin/bash
function print_chars()
{
# 传入的第一个参数指定要打印的字符串
local char="$1"
# 传入的第二个参数指定要打印多少次指定的字符串
local number="$2"
local c
for ((c = 0; c < number; ++c)); do
printf "$char"
done
}
declare -i end=50
for ((i = 1; i <= end; ++i)); do
printf "\e[80D["
print_chars "#" $i
print_chars " " $((end - i))
printf "] %3d%%" $((i * 2))
sleep 0.1s
done
echo
这个脚本定义了一个 print_chars 函数,能够屡次打印同一个字符。
printf "\e[80D["
语句把光标左移 80 列。因为这个进度条的字符总长度小于 80,会挪动最右边,总是从第一列开始输入。
在‘80D’前面的‘[’字符是进度条的结尾第一个字符。
print_chars "#" $i
语句递增打印多个 # 字符,造成进度条往前挪动的成果。
print_chars " " $((end - i))
语句打印多个空格,填充到指定的最初一列,让进度条的完结字符总是打印在同一列。
printf "] %3d%%" $((i * 2))
语句打印进度条的完结字符 ]、以及进度条百分比。
sleep 0.1s
语句暂停 0.1 秒,防止执行过快,看不到进度条的挪动成果。
执行 progressbar.sh
脚本的后果如下:
$ ./progressbar.sh
[##################################################] 100%
这里不是动图,看不到进度百分比跳变。理论执行就能看到。
应用 ANSI 本义码清屏、革除字符
上面的 ANSI 本义码能够用于清屏、革除光标往后的字符。
本义码 | 含意 |
---|---|
Esc[2J | 革除屏幕显示的内容。在 Ubuntu 上测试,光标地位会放弃不变 |
Esc[K | 革除从光标地位到行尾的所有字符(包含光标下的字符) |
Esc[1K | 革除从光标地位到行首的所有字符(包含光标下的字符) |
Esc[2K | 革除光标所在的整行内容 |
留神 :下面的 J、K 都是大写字母。
具体举例说明如下:
$ printf "123456789\e[5D\e[K\n"
1234
$ printf "123456789\e[5D\e[1K\n"
6789
$ printf "123456789\e[5D\e[2K\n"
printf "123456789\e[5D\e[K\n"
命令先光标左移 5 列,停在字符 5 的地位,而后用 \e[K
本义码从光标地位往后革除所有字符,只保留了后面的 1234 字符串。
printf "123456789\e[5D\e[1K\n"
命令应用 \e[1K
本义码从光标地位往前革除所有字符,只保留了前面的 6789 字符串。
printf "123456789\e[5D\e[2K\n"
命令应用 \e[2K
本义码革除光标所在的整行内容,输入内容为空。