![9f3ebe2652a4cf7731638bf5ec8b1b60.png](https://i-blog.csdnimg.cn/blog_migrate/bfc39270608be2dddd4e33220f75f562.jpeg)
引言
无论学习什么编程语言,所接触到的第一个例子必然是打印Hello World!
,在bash当中这个例子是通过如下方式实现的:
echo "Hello World!"
它的输出结果是:
![2e177a0ea2c0ddad53b8486d927aab90.png](https://i-blog.csdnimg.cn/blog_migrate/6005b3ee2af35a55e9f80154af3e7b5f.png)
现在有一个非常有趣的问题就是,如果我想要打印出红色的字体该怎么整呢?
在继续说明echo如何实现这一目标之前,先简要介绍一下我的bash环境:
- Microsoft Windows [版本 10.0.19041.113] (Windows预览体验计划)
- Ubuntu-18.04 WSL version 2
- Windows Terminal (Preview)
- GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
echo基础用法
echo
的作用就是将文本打印到终端,其基本用法就是在echo
后面添上你想要打印出来的语句,如前文的Hello World
例子。
echo
可以接受多个参数,打印的时候会用单个空格将参数们隔开,比如:
![c0d14515a658c098c1a2bc4bf5fca4c3.png](https://i-blog.csdnimg.cn/blog_migrate/0f86fa4e873a32596db221cc0a8d2446.png)
原本以为会打印出Hello World
的例子,实际上打印出来的还是Hello World
,这是因为echo
将Hello
与World
视为两个参数。要想真正打印出Hello World
,需要使用双引号将字符串包起来,使之成为单个参数,如下所示:
![9db2b8b4d312aa3611f7a65121c3d992.png](https://i-blog.csdnimg.cn/blog_migrate/dd36ad24d8ee32edb220f888142479f9.png)
在bash当中,单引号和双引号的作用是不相同的。单引号的表现有点像python当中的r'<string>'
,双引号的则有点像python当中的f'{<var_name>}'
。举个简单的例子就能看明白了:
![9df438e3376f1e871c37f3aa504d9055.png](https://i-blog.csdnimg.cn/blog_migrate/7b088622ec307604665bd761fcf8a5c6.png)
单引号直接原样打印了包含在其中的字符串,双引号则会先将变量转化成其对应的字符串,然后再进行打印。
事实上,在使用echo的时候完全可以不带引号,本小节开篇的第一张图就是一个很好的例子。但是强烈建议带上引号,不带引号可能会让程序出现一些难以预料的后果。比如:
![2eb452665fc6c37f1ca5a971ae04827a.png](https://i-blog.csdnimg.cn/blog_migrate/f7db176ea563ee099dc187d9e6f02b99.png)
你以为输出的内容会带上好几个空格,但实际上只有一个空格出现。所以比较好的习惯就是,但凡使用echo输出内容,就给挂上双引号。
带选项的echo
echo其实还有几个选项可以使用的,使用man echo
就可以发现echo可以接受5个不同的选项,分别是-n
, -e
, -E
, --help
, --version
。这几个选项的含义其实也是非常好记的。--help
自然是打印出echo的帮助文档,--version
用来查看当前echo的版本号。
默认情况下,echo打印完文本后就会自动跳到下一行,加上-n
这个选项以后,echo就会把光标停在原地了,不会自动跳转到下一行,可见示例:
![6a4788e69320f8608edc7e297a15a38b.png](https://i-blog.csdnimg.cn/blog_migrate/a9568d4d5fd15f40e1940271c6c06d0d.png)
默认情况下, echo是不会接受转义字符的,只有带上了-e
的选项,转义字符才会被解释成相应的内容,可见示例:
![88184e95c4e85ea62b30b2db0e5171d1.png](https://i-blog.csdnimg.cn/blog_migrate/471987764dcc686521c686cd2a3fe162.png)
-E
这个选项的含义就和-e
反过来了,就是转义字符一律都不要打印出来,可见示例:
![fcec56d07deb0dc0afae9d4929aa07de.png](https://i-blog.csdnimg.cn/blog_migrate/9fe5f732487cf149b117cecceb60854e.png)
echo的手册当中能够看到所有支持的转义字符,详见下图:
![e37a6ed6cc66dbbbb0fd97bad2d7d919.png](https://i-blog.csdnimg.cn/blog_migrate/53baacd1a0716cc4492974e89486790a.png)
还有两个用的非常多的转义字符,分别是'
, "
,显然这两个转义字符就是为了能够输出单引号和双引号而设计的。
echo的富文本编辑
整了老半天了,怎么还是没有看到富文本编辑? ——@匿名知乎网友
在上一小节的最后一张图里面,我们看到了几个不常见的转义字符,其中的e
就是我们的主角了。 它和ANSI控制码的配合就可以实现我们的富文本编辑了。
简单来说,ANSI控制码就是一些已经定义好了的特殊转义字符。它们都以ESC [
开头,然后后面放上一些看着像乱码一样的东西,就能够实现一些特殊的功能了。
先来看看字体颜色的设置吧。ANSI控制码中可以控制字体的前景色与背景色,它的格式是
e[<foreground-color code>;<background-color code>m
代码中的e
显然就是ESC
的转义符,ESC [
意味着我们要开始整ANSI控制码了,foreground-color code
和background-color code
都是已经定义好了的一些常量,照着拿来用就好了,最后要挂上一个m
,完成整条语句。先看示例:
![3db8490ac79cd70f508f9a40f715610c.png](https://i-blog.csdnimg.cn/blog_migrate/a3031c4155b09a62491337517e0129b1.png)
这里面有一个小问题,那就是这个白色底太长了,我们不想要它这么长的。在输出完想要输出的内容以后,我们再清除先前设定的所有格式 就行了,要用到的代码是e[0m
,可见示例:
![75ca6653d2c271a1a881891f20b89151.png](https://i-blog.csdnimg.cn/blog_migrate/16c79dbcf647253b2aa070f096b1cad2.png)
如果我们只要设置其前景色或者是背景色,只要把相应的代码和分号去掉就可以了。可见示例:
![91c44609c81f9b7fd39c4dd586fbd928.png](https://i-blog.csdnimg.cn/blog_migrate/2123dc62b72e4b58875f3d6addd9d7c3.png)
现在列出所有可用的前景色代码和后景色代码:
![0136d6b48f6f89a95c2d699ba45c432e.png](https://i-blog.csdnimg.cn/blog_migrate/bd3ea3e462dd8dbbdd9c2c4def53b59e.png)
不难看出前景色以3或9开头,从0排到7,后景色以4或10开头,从0排到7,对应的颜色其实是相同的。这里总共给出了16种颜色,如果我们还想要更加丰富的颜色可该咋整呢?
我们还可以使用256色,相应的转义字符如下:
e[38;5;<fore-ground code>me[48;5;<back-ground code>m
给一个具体的实例:
![a7ff108e7a7163b9f2954673bdcca6d9.png](https://i-blog.csdnimg.cn/blog_migrate/e959837744ac53065bb680fc03ce2a23.png)
这里面的前景色代码和后景色代码的取值范围是[0, 255],具体的颜色示例可见下图:
![e4c5c41262581797eede015c0ddfad98.png](https://i-blog.csdnimg.cn/blog_migrate/a4d8be70d67a0e9489e43a7f3cc43aec.jpeg)
对于我的ThinkPad X201i来说,只能够显示256种颜色还是太屈才了,起码得支持RGB全色域才行嘛。在自己的终端支持的情况下,我们是可以使用RGB颜色的。
相应的转义字符如下:
e[38;2;<r>;<g>;<b>me[48;2;<r>;<g>;<b>m左边是前景色,右边是背景色
给一个简单的示例就行了:
![c57b05dfbaaa88d86c0fac158dc40b77.png](https://i-blog.csdnimg.cn/blog_migrate/b820e7c8f5a7be28e0faf7c6217e57bd.png)
关于颜色的设置知道这么多就绰绰有余了,更多的内容可以去翻阅维基百科。
除了设置字体的颜色以外,我们还可以对字体的样式进行一些简单的设置:
- 加粗:
e[1m
; - 下划线:
e[4m
; - 反色显示:
e[7m
;
![d8395c9037603f58ad49046f2901fbe5.png](https://i-blog.csdnimg.cn/blog_migrate/1c1ebd8c22cc4d0fc811c285ed0ee64b.png)
ANSI控制码实现对光标的控制
ANSI控制码可以实现对光标的控制,比如:
- 向上移动光标n行:
e[nA
- 向下移动光标n行:
e[nB
- 向右移动光标n列:
e[nC
- 向左移动光标n列:
e[nD
这里移动光标的时候如果触及到了边界,就不会再移动了。使用这里的ANSI控制码,就可以实现一个非常简单的进度条了。每次输出完内容后,禁止换行,并且将光标挪到最左边,然后继续输出。
for index in {1..100} ; do
echo -ne "e[999D${index}%"
sleep 0.05
done
echo
![4407a86b31e337ed8c25b1a0ef2d6232.gif](https://i-blog.csdnimg.cn/blog_migrate/c36361931f48a0fb8a8a6e2233116e74.gif)
- 隐藏光标,
e[?25l
注:在我的Windows Terminal上面没有用,但在cmd里面有用 - 显示光标,
e[?25h
- 保存光标位置,
e[s
- 恢复上一次保存的光标位置,
e[u
- 将光标移动到下n行的头,
e[nE
- 将光标移动到上n行的头,
e[nF
- 设置光标位置,
e[n;mH
,n代表行,m代表列 - 清屏,
e[nJ
,- 当n=0时,清除光标到屏幕结尾的所有内容 ;
- 当n=1时,清除光标到屏幕开始的所有内容;
- 当n=2时,清除所有内容
- 清除当前行内容,
e[nK
- 当n=0时,清除光标到行尾所有内容;
- 当n=0时,清除光标当行首的所有内容;
- 当n=2时,清除光标所在行的所有内容
小结
更多内容留待后续补充
参考文献
Build your own Command Line with ANSI escape codes