Bash常用快捷键
修改快捷键参考stty命令
| 快捷键 | 说明 |
|---|---|
| ctrl+a | 将光标跳转到命令行开头 |
| ctrl+e | 将光标跳转到命令行末尾 |
| ctrl+左箭头 | 光标向左(前)跳转一个单词,esc+b也可以 |
| ctrl+右箭头 | 光标向右(后)跳转一个单词,esc+f也可以 |
| ctrl+u | 剪切光标到行首之间的内容(也用来快速删除一整行命令) |
| ctrl+k | 剪切光标到行尾之间的内容 |
| ctrl+y | 粘贴剪切的内容 |
| clear | 清屏 |
| ctrl+l | 清屏,同clear命令 |
| exit | 退出当前终端 |
| ctrl+d | 如果命令行中有输入,则终止输入并提交;如果命令行中无输入,则为退出当前终端,同exit命令 |
| ctrl+c | 强制终止当前任务 |
| ctrl+z | 暂停当前任务并放入后台 |
| ctrl+r | 反向搜索执行过的历史命令 |
| # | root用户的命令提示符 |
| $ | 非root用户的命令提示符 |
| > | 次提示符 |
| \ | 延续字符 |
shell介绍
shell简介
shell意为层壳,区别于操作系统Kernel(内核),shell是一个命令行解释器,主要用来与用户交互,将用户的命令解释给操作系统,是用户与操作系统内核交互的桥梁,它提供文件操作、进程控制、环境变量设置、管道和重定向等各种功能,因此,Shell 也是许多脚本和自动化任务的基础。此外,shell还有一套自己的编程语法,用于编写shell脚本,shell脚本支持直接调用Linux系统命令
常见的类Unix操作系统中的Shell程序包括:
- sh(Bourne Shell):是Unix系统上最早的shell,由Stephen Bourne于1977年在AT&T贝尔实验室开发。尽管现在有许多更现代的shell可以使用,但许多Unix系统命令和脚本仍然使用sh作为默认解释器
- Bash(Bourne-Again SHell): bash是Bourne Shell的增强版,兼容sh的命令和脚本,并结合了ksh、csh的有用功能。作为GNU项目的一部分,它具有强大的功能和灵活性,支持命令历史、自动补全、脚本编程等功能,是许多Linux系统的默认Shell
- Csh(C Shell):csh是基于C语言语法的shell,它提供了类似于C语言的语法结构和编程特性,由Bill Joy于1978年开发
- Tcsh(TC Shell):Tcsh是C Shell的改进版本,提供了更多的功能和灵活性
- Fish(Friendly Interactive Shell):Fish是一个用户友好的交互式shell软件,具有直观的语法和自动补全功能,还提供了颜色高亮和语法提示等功能,被广泛包含于如 Debian、Ubuntu、Fedora、Gentoo、Arch 等操作系统中
- Ksh(Korn Shell):由贝尔实验室的David Korn在1983年基于Bourne shell的源码开发,它结合了Bourne Shell和C Shell的特性,并引入了许多新的功能
- Zsh(Z Shell):由普林斯顿大学的Paul Falstad开发,它包含了 bash,ksh,tcsh 等其他shell中许多优秀功能,可以作为bash的替代品,它也是macOS 10.15及新版系统的默认shell
在这些众多的shell中,有一些shell软件有类似的语法和特性,由此形成了两大家族:Bourne Shell家族:通常为Linux的默认使用终端,包括sh、ksh、Bash、psh、zsh。以及C Shell家族:包括csh、tcsh,语法与C语言类似,主要用于BSD版Unix系统。
切换shell
查看/etc/shells文件可获取当前Linux支持的shell列表,绝大多数Linux发行版默认使用Bash作为命令解释器,直接输入其他shell名可进行切换,通过exit命令返回默认的Bash终端
父子shell
默认情况下,系统会在用户登录时根据/etc/passwd文件第7字段的设置启动用户的默认shell,这是一个父shell,如果此时输入bash或其他shell的启动命令,会创建一个新的shell程序,这个shell程序是一个子shell。
创建子shell可以保持父子进程环境的纯洁性,创建子shell时,只有部分父进程环境会被复制到子shell中,因此子shell会在一个相对纯洁的环境中执行任务,但这也会造成父shell中的一些变量(如用户自定义的局部变量)无法被子shell中继承使用。在子shell中执行一些独立任务,或者修改一些环境也不会影响到父进程的执行。但是创建子shell成本不菲,它会显著占用一部分系统资源
以下操作会创建一个子shell:
- 通过bash等命令显式调用shell解释器,会启动一个新的子shell
- 通过bash filename.sh或./filename.sh方式执行shell脚本时,会创建一个子shell执行该脚本。相对的,通过source filename.sh或.filename.sh方式执行脚本,会在当前shell中执行而不会创建子shell
- 在命令中使用管道符|时,shell会创建子shell,管道两边的命令都会在单独的子shell中执行。
- 使用反引号` `或$()执行命令替换时,命令会在子shell中执行
- 将命令放到( )中,所有括号中的命令会在子shell中执行,这是最直接创建子shell的方式,通常用来执行多个需要在同一个shell环境中执行的一组命令
- 使用&将任务放到后台执行时,为了不阻塞当前shell执行其他任务,bash会在后台创建子shell执行命令
查看父子shell的创建关系
子shell也可以创建另一个子shell,产生嵌套,通过ps -f命令查看shell程序的PPID来查找其父进程
也可以通过输出环境变量BASH_SUBSHELL来查看当前bash有没有生成子shell,如果该命令返回0,则表明没有子shell,返回1或其他更大的值,就表明有相应数量的子shell。但该命令需要在父shell环境下执行,因此一般在命令分组并形成进程列表时使用
bash shell程序可使用命令行选项修改shell启动方式,以下为bash中可用的命令行参数
| 参数 | 说明 |
|---|---|
| -c string | 从string中读取命令并进行处理 |
| -i | 启动一个能够接收用户输入的交互shell |
| -l | 以登录shell的形式启动 |
| -r | 启动一个受限shell,用户会被限制在默认目录中 |
| -s | 从标准输入中读取命令 |
父子shell的使用场景
如果命令或脚本需要在一个纯净的隔离环境下执行,或者希望执行某个操作但不改变当前的shell环境,创建子shell十分有用,但需要注意创建子shell带来的资源占用问题
内建命令与外部命令
外部命令
外部命令,又被称为文件系统命令,是存在于bash shell之外的程序。它们并不是shell程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中,可以使用which或type -a命令找到命令位置。执行外部命令时,会创建一个该命令对应的子进程,相对于内建命令来说,外部命令需要花费时间和资源来设置新子进程的环境
内建命令
内建命令不需要使用子进程来执行,它们已经和shell编译成了一体,在执行时速度更快,消耗的资源更少。常见的内建命令有cd、echo、pwd、history、alias、continue、exit、jobs、kill等
可以使用type命令来查看某个命令是否为内建命令
有些命令有多种实现方式,如:echo和pwd既有内建命令又有外部命令,默认使用内建命令,如果需要使用外部命令,则指定命令的具体路径即可。可以用type -a命令查看命令的不同实现
命令的执行优先级
- 第一顺位执行通过绝对路径或相对路径执行的命令
- 第二顺位执行自定义的命令别名
- 第三顺位执行bash内部命令
- 第四顺位执行$PATH环境变量定义的第一个命令
命令分组执行
可以在一行中指定多个命令,命令之间使用分号(;)分隔,称为命令列表,这些命令会依次执行
可以使用大括号或小括号将这些命令组合在一起,以便在特定情况(如在if-then语句中)一起执行,这称之为命令分组,主要有两种不同的命令分组:
使用大括号{ }将多个命令组合在一起,可以在当前shell环境中执行,该方法也可用于shell脚本中if-then语句的结构控制
{ pwd ; cd /etc ; ls }如果将命令列表写在括号里,则shell会创建一个子shell执行这些命令,称为进程列表,这样可以使用多个子shell进行多进程处理
创建1个子shell,输出值为1 (pwd ; ls ; cd /etc ; pwd ; ls ; echo $BASH_SUBSHELL) 括号可以嵌套,创建多个子shell进行多进程处理,创建了2个子shell(父shell创建子shell,子shell又创建了它的子shell),输出值为2 ( pwd ; (echo $BASH_SUBSHELL))
创建协程
shell中的协程用于在后台创建一个子shell,并在该shell中执行命令,其实就相当于使用&将命令置入后台模式,但其特点在于我们可以为该协程命名,并且该协程创建时会自动创建一个匿名管道,并将子shell的输入输出重定向到这个管道,实现在 Bash 脚本中并发地执行子进程,并与该子进程进行双向数据通信的功能
协程的创建需要使用命令coproc,其语法为:
coproc 协程名 { 命令1; 命令2; }
如果不指定协程名,则默认为COPROC,之后命令会被置入后台模式,返回后台作业号和进程ID
Bash的内建命令
Bash的启动方式
bash [选项] [脚本文件] [参数]
- -c “字符串”:执行字符串中的命令
- -i 启动交互式bash
- -l 或–login:模拟登录Shell,加载用户环境配置(如/etc/profile、~/.bash_profile等文件)
- -s 从标准输入读取命令,通常结合管道和重定向符传递脚本内容
- -r 以受限模式(Restricted Shell)启动bash,限制用户操作,用户将无法执行以下操作:
- 使用cd命令改变当前目录
- 设置或更改 $PATH, $SHELL, $ENV, $BASH_ENV 等变量
- 使用 exec 执行其他程序
- 使用重定向 >、>> 等创建/改写文件
- 调用包含 / 的命令(如 /bin/ls)
- -v 逐行显示每一行命令(不将变量替换为值),然后执行,通常用来观察脚本的执行流程
- -x 逐行显示每一行命令,并将命令中的变量替换为实际值,输出的命令行首会添加+前缀,通常用来调试变量、参数值是否正确
- -n 检查语法错误但不执行,仅验证脚本语法正确性
- -e 严格模式,遇到错误立即退出,防止错误蔓延
- -u 遇到未定义变量时报错,检查是否有未定义变量
history历史命令
在bash中执行过的命令会被缓存在内存中,方便重复调用,当shell退出或用户登出时会被写到用户对应的.bash_history历史命令记录文件中
history [选项] [历史命令保存文件]查看使用过的命令,可以在后面加一个值指定显示n条命令
- -c 清空历史命令
- -w 把缓存的历史命令写入历史命令保存文件~/.bash_history中
- -a 将缓存的历史命令追加到历史命令保存文件中
- -d 值 删除该条历史命令记录
- -s 字符串 将该字符串添加到当前会话的命令历史中,但不执行
调用历史命令
- 可通过上下箭头调用之前执行的命令
- !!再次执行上一次执行的命令
- !n再次执行第n条历史命令(序号以history列出的序号为准)
- !字符串再次执行最后一次以该字符串开头的命令
alias自定义命令名
alias查看所有自定义的命令
alias 别名=’原命令’自定义命令名,原命令依旧可用
使用命令定义的命令名只能临时生效,且只在当前shell中生效,系统重启后将丢失,要永久生效需将自定义的命令添加到文件/用户名/.bashrc中
删除自定义的命令:
unalias 别名
type查询命令类型
查看所指定的命令是shell 内建命令、外部可执行文件,还是其他类型
type [选项] 命令
- -a 查看所有可能的命令类型,有的命令可能同时有shell内建、外部二进制文件、用户别名等多种类型,该选项会列出所有情况
- -t 只显示命令类型,而不显示命令路径,返回类型可能有:alias(别名)、builtin(内建命令)、file(外部命令)、function(定义的函数)、keyword(shell保留的关键字)
- -p (小写)只显示命令路径,如果命令是shell内建命令或别名,使用此选项不会有输出
- -P (大写)在PATH中查找该命令,无论该命令是何种类型,都返回其路径,该选项常被用来在shell脚本中查询并精确执行某命令,如$(type -P curl)
- -f 不在shell函数中查找,即不将命令视为函数来查找
command执行原始命令
当系统中创建了alias别名和shell函数时,如果用户不想执行这些别名或shell函数,可以使用command来执行原始的Linux命令,常用来在脚本中安全地执行某个命令,而不受用户环境影响
command [选项] 命令 [参数]
- 默认情况下,通过command执行的命令会无视alias或shell函数,执行系统原装的命令,默认前往PATH路径下查找该命令,包括用户自行在PATH中添加的路径
- -p 在PATH中查找命令时,无视用户添加的PATH路径,而只在系统默认的PATH路径下查找(通常是/bin和/usr/bin等系统默认命令路径),以免用户在PATH中添加了非系统原生的命令路径
- -v 显示关于命令的信息(是别名、函数、内置命令还是磁盘上的可执行文件),常用来在脚本中测试是否安装了某个命令,相较于使用type -P检测,command -v是POSIX标准,更推荐在可移植脚本中使用
- -V 显示更详细的命令描述信息
if command -v apt &>/dev/null; then
sudo apt install -y .......
elif command -v yum &>/dev/null; then
sudo yum install -y .......
elif command -v dnf &>/dev/null; then
sudo dnf install -y .......
else
echo "不支持当前包管理器安装"
fi
set管理shell功能
set命令用来查看或修改当前shell的设置,如打开或关闭shell的调试、安全、错误处理等功能,修改shell的位置变量等,它的功能十分强大,这里只整理部分可能用到的常用功能
set [-或+] [选项] [--] [参数]
- 不添加任何选项和参数时,set会打印所有shell变量和函数,包括环境变量、用户定义变量、位置参数、全局函数等
- 当为set不提供任何选项,只提供参数时,set会将位置参数$1,$2..设置为对应参数
- -会开启一个功能选项,+会关闭一个选项
- e 一旦任何命令返回非0状态,立刻退出脚本
- v 逐行显示每一行命令(不将变量替换为值),然后执行
- x 逐行显示每一行命令,并将命令中的变量替换为实际值,输出的命令行首会添加+前缀
- u 使用未定义变量时报错
- n 只做语法检查不执行脚本
- [-/+o 特殊控制名] 开启或关闭特殊设置
- history:启用命令历史记录,对于交互式shell,该配置默认开启
- ignoreeof:交互式shell在读取到EOF时不会退出
- pipefail:管道中任意命令失败时,整个管道视为失败
- vi:使用vi风格的编辑界面,这会影响用于read -e 的编辑界面
- emacs:使用emacs风格的编辑界面,这会影响用于read -e 的编辑界面
:空操作
不执行任何操作,总是返回成功(退出状态码为0),一般可用作占位符
mapfile将标准输入存储到数组
该用于将输入(如文件或管道数据)逐行读取到数组中,该命令的效率高于while read循环
mapfile [选项] [数组名]
- 从标准输入或文件中读取行数组中,如果未指定数组,则使用默认的数组名MAPFILE
- -d “行终止符”:指定每个行的终止符,而不是默认的换行符,-d “”指定空字符串,将使用NUL作为行终止符
- -n 值N:只输入N行,如果值为0将输入所有行到数组
- -u 文件描述符:从该文件描述符指向的文件读取数据
- -O 索引值:指定索引值,从该值开始存储,默认从0存储
- -s 值N:跳过前N行,不存储到数组
- -t 输入时删除行尾的行终止符
- -C 回调函数名:在每次读入行时执行回调函数,回调函数中可以使用$1(下一个存入的数组索引),$2(要存入的行内容)引用对应的数据,mapfile命令会自动传递这2个参数,如果不指定-c,默认每5000行执行一次回调,以避免性能问题
- -c 值N:和-C选项搭配使用,每读取N行执行一次回调
arr=(aaaa bbbbb)
process_line() {
echo "下一个索引: $1" #依次输出3,4
}
mapfile -t -O 3 -c 1 -C process_line arr <<EOF
hello
shell
EOF
exec命令
exec命令的主要功能有两个
替换当前shell进程
- -c 清除所有环境变量(除了HOME、SHELL、PATH、TERM、MAIL、USER和LOGNAM)
- -l 启动一个新shell执行对应的命令,该shell以登录shell的身份工作
当使用exec命令执行命令或可执行文件时,新执行的程序会替换当前的shell进程。exec命令会将指定的命令或程序加载到当前shell进程的内存空间中,并替换 shell 进程的执行上下文,包括内存代码段、数据段、堆栈中的数据等,同时,新进程会继承原进程的大部分环境和信息,包括进程PID、环境变量、当前工作目录、打开的文件描述符、用户和用户组ID、进程优先级、以及对进程的资源限制(如内存限制、文件大小限制)等信息,这样可以在不创建新进程的情况下,执行新的功能和程序,极大程度上节省了用于创建新进程消耗的系统资源,可以有效减少进程数量并简化进程管理。
该命令可用于在不创建新进程或子shell的情况下切换shell并替换当前的shell进程,通过exec命令切换,Linux会保持shell的PID、用户和用户组ID、当前工作目录等环境不变,也不会创建子shell消耗更多的系统资源
该命令也可以用其他程序替换当前的shell进程,例如,在脚本的最后一行使用 exec 来启动一个长期运行的程序,当脚本即将运行结束,shell的使命也即将完成,通过exec命令让新的程序替换shell进程,而不再需要创建新的进程,可以有效节约系统资源
此外,exec命令还被用于以下场景:
- 当某个进程认为自己不能再为系统和用户作出任何贡献时,就可以调用exec命令让新的进程替代自己,如:一些守护进程,或用于系统初始化启动的进程,当系统完成启动,这些进程的使命已经完成,exec命令可以使新进程接管自己的初始化环境,减少进程间的通信和数据拷贝,提高系统性能
- 在一些特定环境中,使用exec命令可以保证某个关键任务完全接管当前进程,而不会有多余的 shell 进程存在
- 可以用于动态加载新程序和脚本,在其环境不变的情况下执行新脚本,而无需额外创建进程
- 在某些需要严格控制权限的环境中,用 exec 替换当前进程可以确保新的进程继承当前进程的所有权限和环境,使进程在受限的环境中启动并继承了相应权限
修改文件描述符
exec 命令还可以用来重定向文件描述符。在这种用法中,exec 并不会替换当前的 shell 进程,而是会替换脚本的执行环境,该命令可用来重定向整个脚本的标准输入输出文件,或者关闭不需要的文件描述符
<()与>()重定向
<(命令)和>(命令)是Bash特有的进程替换(Process Substitution)语法,用于将命令的输入或输出“伪装”为一个文件路径,以供其他命令使用。
使用时,Bash会创建一个临时文件描述符,然后将该文件名作为参数传入命令,该语法适合一些需要文件名或路径作为参数的命令中,如:cat、diff、read、tar等
通配符
通配符(Wildcard)是shell中用来进行文件或路径匹配的操作符,常用ls、cp、rm等命令,它的功能和正则表达式(Regular Expression)很像,但本质上是不同的工具
常用通配符
| 符号 | 作用 |
|---|---|
| * | 匹配任意长度的任意字符,可以为空 |
| ? | 匹配单个任意字符 |
| [abc] | 匹配a或b或c中的任意一个字符,相当于”或” |
| [!abc]或[^abc] | 匹配不包括a、b、c在内的任意一个字符,相当于”非” |
{..}花括号扩展
花括号符{..}可以扩展花括号中的值,通常需要和其他字符串搭配,用来快速和其他字符串生成组合值,该语法为Bash独有,大多数shell不支持
| 语法 | 作用 |
|---|---|
| {a,b,c} | 将a,b,c扩展到其他字符串中 |
| {1..4}或{a..z} | 将该区间的所有值或字母拓展到其他字符串中 |
扩展通配符
扩展通配符需要先执行shopt -s extglob来启用extglob扩展模式
| 通配符 | 作用 | 示例 |
|---|---|---|
| ?(pattern) | 匹配0次或1次 pattern | file?(.bak) 匹配 file 或 file.bak |
| *(pattern) | 匹配0次或多次 pattern | dir*(/tmp) 匹配 dir、dir/tmp、dir/tmp/tmp… |
| +(pattern) | 匹配1次或多次 pattern | log+(.old) 匹配 log.old、log.old.old… |
| @(pattern1|pattern2) | 匹配 pattern1 或 pattern2 | file@(.txt|.csv) 匹配 file.txt 或 file.csv |
| !(pattern) | 匹配 不符合 pattern 的内容 | !(*.bak) 匹配所有非 .bak 文件 |
POSIX字符类
POSIX标准预定义了一些常用的字符类,方便在处理字符串、文件名等情况时直接调用,在grep、sed、awk等Linux命令中,这些预定义的字符类需要在[ ]中使用,在tr等命令中则可以直接使用
| 通配符 | 匹配的范围 | 字符 |
|---|---|---|
| [:alnum:] | 匹配字母或数字 | [a-zA-Z0-9] |
| [:alpha:] | 匹配字母 | [a-zA-Z] |
| [:digit:] | 匹配数字 | [0-9] |
| [:lower:] | 匹配小写字母 | [a-z] |
| [:upper:] | 匹配大写字母 | [A-Z] |
| [:space:] | 空白字符 | 空格、\t、\n等 |
| [:blank:] | 空格和制表符 | 空格和\t |
| [:punct:] | 标点符号 | !@#$%^&*()等 |
| [:graph:] | 可见字符 | 非空白、非控制字符 |
| [:print:] | 可打印字符 | 包括空格在内的可打印字符 |
| [:cntrl:] | 控制字符 | ASCII 0-31 和 127 |
| [:xdigit:] | 十六进制数字字符 | [0-9A-Fa-f] |
环境变量
bash shell使用环境变量(environment variable)来存储有关shell的会话和工作环境,并将这些信息存储在内存中,以便程序或shell脚本能够轻松访问到这些数据,一般情况下,环境变量均使用大写的变量名
全局环境变量
全局环境变量该shell和其创建的子shell中均有效,以下为查询全局环境变量的命令
- printenv查看所有全局环境变量
- -0 每行输出末尾输出空字符(null),而不是换行符,以便其他程序解析输出
- env查看所有全局环境变量
- printenv 变量名查看指定环境变量
- echo $变量名查看指定环境变量
定义全局环境变量需要使用export关键字
- export 变量名=值 定义全局环境变量
- unset 变量名 删除变量
父shell中创建的全局环境变量在子shell中也有效,且如果此时在子shell中修改该变量的值,不会影响其在父shell中的值,修改后的值只在子shell中有效
局部环境变量
局部环境变量只能在定义它们的shell中有效,父shell中的局部环境变量无法在子shell中访问到。Linux中没有只显示局部环境变量的命令,但可以通过set命令查看所有环境变量,包括局部变量、全局变量以及用户定义变量
定义局部环境变量的方法和定义局部自定义变量的方法一样,不需要加export关键字,只需要将变量名大写用于识别该变量是一个环境变量即可
Bash中的环境变量
以下为bash shell种已经定义好的环境变量,可以直接调用,有些环境变量的值为空,因此执行set命令时不一定会列出所有变量
| 变量名 | 说明 |
|---|---|
| HOME | 当前用户的主目录 |
| UID | 当前用户的真实用户ID(数字形式) |
| EUID | 当前用户的有效用户ID(数字形式) |
| IFS | shell用来将文本字符串分割成字段的一系列字符 |
| 当前用户收件箱的文件名 | |
| MAILPATH | 冒号分隔的当前用户收件箱的文件名列表 |
| OPTARG | getopts命令处理的最后一个选项参数值 |
| OPTIND | getopts命令处理的最后一个选项参数的索引号 |
| PATH | shell查找命令的目录列表,由冒号分隔 |
| PS1 | shell命令行界面的主提示符 |
| PS2 | shell命令行界面的次提示符 |
| CDPATH | cd命令的搜索路径,切换路径时,cd命令会先尝试在当前目录下查找指定目录并切换过去,如果当前目录下并没有指定的目录,则cd命令会前往该变量设置的路径下查找并切换,可以指定多个路径用冒号分隔 |
| BASH | 当前shell实例的全路径名 |
| BASH_ALIASES | 含有当前已设置别名的关联数组 |
| BASH_ARGC | 含有传入子函数或shell脚本的参数总数的数组变量 |
| BASH_ARCV | 含有传入子函数或shell脚本的参数的数组变量 |
| BASH_CMDS | 关联数组,包含shell执行过的命令的所在位置 |
| BASH_COMMAND | shell正在执行的命令或马上就执行的命令 |
| BASH_ENV | 设置了的话,bash脚本会在执行前读取变量中的文件,读取文件中设置的变量,并执行其中的命令 |
| BASH_EXECUTION_STRING | 使用bash -c选项传递过来的命令 |
| BASH_LINENO | 含有当前执行的shell函数的源代码行号的数组变量 |
| BASH_REMATCH | 只读数组,在使用正则表达式的比较运算符=~进行肯定匹配(positive match)时,包含了匹配到的模式和子模式 |
| BASH_SOURCE | 含有当前正在执行的shell函数所在源文件名的数组变量 |
| BASH_SUBSHELL | 当前子shell环境的嵌套级别(初始值是0) |
| BASH_VERSINFO | 含有当前运行的bash shell的主版本号和次版本号的数组变量 |
| BASH_VERSION | 当前运行的bash shell的版本号 |
| BASH_XTRACEFD | 若设置成了有效的文件描述符(0、1、2),则’set -x’调试选项生成的跟踪输出,可被重定向。通常用来将跟踪输出到一个文件中 |
| BASHOPTS | 当前启用的bash shell选项的列表 |
| BASHPID | 当前bash进程的PID |
| COLUMNS | 当前bash shell实例所用终端的宽度 |
| COMP_CWORD | COMP_WORDS变量的索引值,后者含有当前光标的位置 |
| COMP_LINE | 当前命令行 |
| COMP_POINT | 当前光标位置相对于当前命令起始的索引 |
| COMP_KEY | 用来调用shell函数补全功能的最后一个键 |
| COMP_TYPE | 一个整数值,表示所尝试的补全类型,用以完成shell函数补全 |
| COMP_WORDBREAKS | Readline库中用于单词补全的词分隔字符 |
| COMP_WORDS | 含有当前命令行所有单词的数组变量 |
| COMPREPLY | 含有由shell函数生成的可能填充代码的数组变量 |
| COPROC | 占用未命名的协进程的I/O文件描述符的数组变量 |
| DIRSTACK | 含有目录栈当前内容的数组变量 |
| EMACS | 设置为’t’时,表明emacs shell缓冲区正在工作,而行编辑功能被禁止 |
| ENV | 如果设置了该环境变量,在bash shell运行之前会读取该变量指定路径中的文件,如果未设置,Bash 会默认读取用户的”HOME/.bashrc”文件以设置环境变量,该变量方便用户自定义bash启动时的环境变量(仅用于当bash shell以POSIX模式被调用时) |
| FCEDIT | 供fc命令使用的默认编辑器 |
| FIGNORE | 在进行文件名补全时可以忽略后缀名列表,由冒号分隔 |
| FUNCNAME | 当前执行的shell函数的名称 |
| FUNCNEST | 当设置成非零值时,表示所允许的最大函数嵌套级数(一旦超出,当前命令即被终止) |
| GLOBIGNORE | 冒号分隔的模式列表,定义了在进行文件名扩展时可以忽略的一组文件名 |
| GROUPS | 含有当前用户属组列表的数组变量 |
| histchars | 控制历史记录扩展,最多可有3个字符 |
| HISTCMD | 当前命令在历史记录中的编号 |
| HISTCONTROL | 控制哪些命令留在历史记录列表中 |
| HISTFILE | 保存shell历史记录列表的文件名(默认是.bash_history) |
| HISTFILESIZE | 最多在历史文件中存多少行 |
| HISTTIMEFORMAT | 如果设置了且非空,就用作格式化字符串,以显示bash历史中每条命令的时间戳 |
| HISTIGNORE | 由冒号分隔的模式列表,用来决定历史文件中哪些命令会被忽略 |
| HISTSIZE | 最多在历史文件中存多少条命令 |
| HOSTFILE | shell在补全主机名时读取的文件名称 |
| HOSTNAME | 当前主机的名称 |
| HOSTTYPE | 当前运行bash shell的机器 |
| IGNOREEOF | shell在退出前必须收到连续的EOF字符的数量(如果这个值不存在,默认是1) |
| INPUTRC | Readline初始化文件名(默认是.inputrc) |
| LANG | shell的语言环境类别 |
| LC_ALL | 定义了一个语言环境类别,能够覆盖LANG变量 |
| LC_COLLATE | 设置对字符串排序时用的排序规则 |
| LC_CTYPE | 决定如何解释出现在文件名扩展和模式匹配中的字符 |
| LC_MESSAGES | 在解释前面带有$的双引号字符串时,该环境变量决定了所采用的语言环境设置 |
| LC_NUMERIC | 决定着格式化数字时采用的语言环境设置 |
| LINENO | 当前执行的脚本的行号 |
| LINES | 定义了终端上可见的行数 |
| MACHTYPE | 按“CPU-公司-系统”(CPU-company-system)格式定义的系统类型 |
| MAPFILE | 一个数组变量,当mapfile命令未指定数组变量作为参数时,它存储了mapfile所读入的文本 |
| MAILCHECK | shell查看新邮件的频率(以秒为单位,默认值是60) |
| OLDPWD | shell之前的工作目录 |
| OPTERR | 设置为1时,bash shell会显示getopts命令产生的错误 |
| OSTYPE | 定义了shell所在的操作系统 |
| PIPESTATUS | 含有前台进程的退出状态列表的数组变量 |
| POSIXLY_CORRECT | 设置了的话,bash会以POSIX模式启动 |
| PPID | bash shell父进程的PID |
| PROMPT_COMMAND | 设置了的话,在命令行主提示符显示之前会执行这条命令 |
| PROMPT_DIRTRIM | 用来定义当启用了\w或\W提示符字符串转义时显示的尾部目录名的数量。被删除的目录名会用一组英文句点替换 |
| PS3 | select命令的提示符 |
| PS4 | 如果使用了bash的-x选项,在命令行之前显示的提示信息 |
| PWD | 当前工作目录 |
| RANDOM | 返回一个0~32767的随机数(对其的赋值可作为随机数生成器的种子) |
| READLINE_LINE | 当使用bind –x命令时,存储Readline缓冲区的内容 |
| READLINE_POINT | 当使用bind –x命令时,表示Readline缓冲区内容插入点的当前位置 |
| REPLY | read命令的默认变量 |
| SECONDS | 自从shell启动到现在的秒数(对其赋值将会重置计数器) |
| SHELL | bash shell的全路径名 |
| SHELLOPTS | 已启用bash shell选项列表,列表项之间以冒号分隔 |
| SHLVL | shell的层级;每次启动一个新bash shell,该值增加1 |
| TIMEFORMAT | 指定了shell的时间显示格式 |
| TMOUT | select和read命令在没输入的情况下等待多久(以秒为单位)。默认值为0,表示无限长 |
| TMPDIR | 目录名,保存bash shell创建的临时文件 |
环境变量配置文件
用户登录shell时,shell程序会读取环境变量配置文件作为初始化环境,用户可以修改这些文件来指定shell启动时自动执行的任务,以及指定一些环境变量值
全局配置文件
对所有用户生效
- /etc/profile 主要的配置文件,也是用户登录时最先读取的文件,用于保存全局环境变量和shell参数,并调用其他配置文件
- /etc/profile.d/.sh后缀文件 由profile调用
- /etc/bashrc 用于保存bash相关的全局环境变量、函数、命令别名,如PS1等bash终端的环境
/etc/profile配置文件是最主要的配置文件,其中几个常见变量的作用:
| 变量 | 作用 |
|---|---|
| USER | 当前用户 |
| LOGNAME | 当前用户名,配置文件中LOGNAME=$USER,因此同USER |
| 用户邮箱 | |
| HOSTNAME | 主机名 |
| HISTSIZE | 历史命令保存条数 |
| umask | 设置文件默认权限 |
用户配置文件
只对单一用户生效,每个用户都有自己的配置文件,root用户位于/root下,普通用户位于/home/用户名下,默认隐藏,需要使用ls -a命令才能看见文件
- $HOME/.bash_profile 用户个人的/etc/profile文件,保存用户自定义的环境变量,该文件会在用户登录时读取,且一般会在文件中调用其他配置文件(如下面的.bashrc)
- $HOME/.bashrc 写有用户自定义的命令别名、函数等,该文件会在打开一个新的交互式bash时都读取一次
- $HOME/.bash_logout 用户注销时执行的环境变量配置文件,可以写一些我们希望系统关机时执行的操作,如备份日志等
- $HOME/.bash_history 记录用户执行过的命令
部分Linux发行版还可能会提供如:$HOME/.bash_login、$HOME/.profile等文件,其作用一般和$HOME/.bash_profile一样,shell一般会优先执行$HOME/.bash_profile
不重启就使配置文件生效
直接执行任一命令
- source 文件名
- .配置文件名
不同启动方式读取的配置文件
日常使用时,启动bash一般分为3种方式,每种方式都会读取不同的配置文件
- 登录用户账户时作为默认启动的交互式shell
- 通过bash等命令切换创建的非登录交互式子shell
- 执行脚本或任务启动的非交互式shell,如:执行脚本、使用at、cron等命令后台执行定时任务、通过脚本或()等方式启动的子shell
作为默认登录shell启动时,bash会依次读取全局/etc/profile文件,以及用户的$HOME/.bash_profile文件,而绝大多数Linux发行版用户$HOME/.bash_profile文件会调用$HOME/.bashrc文件,而$HOME/.bashrc文件又会调用/etc/bashrc文件,因此一般情况下,登录shell会依次加载/etc/profile、$HOME/.bash_profile、$HOME/.bashrc、/etc/bashrc文件
而作为非登录(但交互式)shell启动时,bash不会访问/etc/profile、$HOME/.bash_profile等文件,只会读取$HOME/.bashrc文件,而绝大部分Linux发行版$HOME/.bashrc文件通常包含了对/etc/bashrc的调用,因此它会依次读取$HOME/.bashrc、/etc/bashrc文件。由于非登录shell是从父shell启动的,因此/etc/profile、$HOME/.bash_profile文件中的全局环境变量也会从父shell中继承下来。
作为非交互式shell启动时,bash shell会检查BASH_ENV 环境变量,如果该变量指定了文件,shell会执行该文件里的命令,并读取里面设置的变量。但在绝大多数Linux发行版中,这个变量一般为空,因此非交互式shell一般不会读取配置文件。但该方式启动的shell,若脚本直接将当前shell作为脚本的执行shell,则所有当前shell中已加载的局部变量和全局变量,都可以在脚本中使用。如果脚本中通过诸如进程列表等方式创建了子shell,而其父shell在其加载的/etc/profile、$HOME/.bashrc等(具体加载哪些文件取决于该父shell的启动方式)文件中使用export声明了全局变量,用于执行脚本的子shell会继承这些变量。
环境变量的持久化
通过赋值方式创建的变量保持于内存中,如果退出shell这些变量会失效,可以将这些环境变量写于配置文件中实现变量的持久化。
对于所有用户都可能用到的环境变量,尽量避免将全局的环境变量放在/etc/profile文件中,该文件会在系统升级时被覆盖,可以在/etc/profile.d目录中创建一个.sh结尾的文件,将全局环境变量放在该文件中,然后再在profile文件中加载该目录下的内容。
对于个人用户,可以将环境变量存放于$HOME/.bashrc文件中,但注意,如果需要在脚本中调用某些自定义环境变量,由于脚本启动的一般是非交互式shell,所以需要先检查是否设置了BASH_ENV 环境变量,如果有则需要将环境变量存放在对应的文件中;如果没有,则考虑在其父shell会读取的文件中将环境变量声明为export或在脚本中设置一个新的。
终端控制
ANSI转义字符序列
为了控制终端的显示和行为,ANSI标准定义了一系列用于控制终端输出选项的字符序列,称为ANSI转义字符序列(Escape Sequence)。这些转义字符序列中ASCII码表0到31(0x00–0x1F)之间的字符称为C0控制字符,C0字符通常用于基本的文本控制和终端操作,如:回车(CR)、换行(LF)、制表符(TAB)等。由于原有的控制字符功能不够全面,为了实现更多的终端控制功能,ASCII码表扩展出了值在128-159(0x80–0x9F)之间的C1控制字符,C1控制字符提供了更多扩展的高级控制功能,包括光标控制、颜色设置、字符集切换、设备控制等
CSI序列
C1控制字符中用于控制光标、设置文本样式和颜色以及实现屏幕的清除、局部刷新等操作的控制字符称为CSI(Control Sequence Introducer)字符,CSI字符序列以ESC(\x1b)开头,并紧接一个[(代表CSI),将ESC转换为ASCII码后,控制字符在代码中常写为\e[或\x1b[或\033[,完整的CSI控制语句为:
\e[参数1;参数2;参数3…函数名
- \e[ 为转义字符引导头
- 中间参数部分可以由0个或多个数字组成,多个数字间用分号分隔
- 函数名为需要调用的CSI函数功能名称
函数
CSI提供了很多用于光标控制、屏幕控制、字符渲染的函数
光标控制
| 函数 | 举例 | 功能 |
|---|---|---|
| A | \e[nA | 光标上移n行(默认1) |
| B | \e[nB | 光标下移n行(默认1) |
| C | \e[nC | 光标左移n行(默认1) |
| D | \e[nD | 光标右移n行(默认1) |
| E | \e[nE | 光标下移n行(默认1),非标准 |
| F | \e[nF | 光标上移n行(默认1),非标准 |
| G | \e[nG | 光标移动至当前行的n列,非标准 |
| H | \e[x;yH | 光标移动到x行y列 |
| s | \e[s | 保存光标位置 |
| u | \e[u | 取出光标位置 |
| l | \e[?25l | 隐藏光标 |
| h | \e[?25h | 显示光标 |
屏幕控制
| 函数 | 举例 | 功能 |
|---|---|---|
| J | \e[nJ | 清除指定范围内的屏幕,0为光标位置到屏幕末尾,1为光标位置到屏幕开头,2为全屏幕 |
| K | \e[nK | 清除该行的指定范围,0为光标到行尾,1为光标至行头,2为整行 |
| S | \e[nS | 整页向上滚动n行,非标准 |
| T | \e[nT | 整页向下滚动n行,非标准 |
修改字体样式
终端中最为常用的转义序列还是用于修改终端字体颜色、背景颜色和显示效果的函数和参数,即SGR(Set graphics mode)函数m,常用于配合echo语句输出不同样式的提示信息,修改终端样式的转义字符序列一般为:
\e[参数m
在指定多个参数时,转义字符序列通常为:
\e[字体样式;字体颜色;背景色m
参数不分先后顺序,指定多个同类样式时,后面的样式将覆盖前面的样式(如:指定多个背景色,只有最后一个背景色会生效)
恢复默认
\e[0m表示取消所有设置的属性(包括颜色、加粗、闪烁等效果),使后续输出内容恢复默认属性
文字效果
| 设置效果代码 | 效果 | 取消效果代码 |
|---|---|---|
| 1 | 加粗高亮 | 21 |
| 2 | 变暗(未被广泛支持) | |
| 3 | 斜体(未被广泛支持) | |
| 4 | 下划线 | 24 |
| 5 | 缓慢闪烁,低于每分钟150次 | 25 |
| 6 | 快速闪烁,每分钟150次以上(未被广泛支持) | |
| 7 | 反转背景色和前景色 | 27 |
| 8 | 隐藏,常用于密码(未被广泛支持) | 28 |
| 9 | 划掉文字(未被广泛支持) | |
| 10 | 默认字体 | |
| 11-19 | 替代字体 | |
| 20 | 尖角体 |
字体颜色(前景色)
以下颜色在不同终端中被定义了不同的RGB值,且没有一个通用标准,因此不同终端中的样式可能有所不同,详情可参考:ANSI escape code
| 代码 | 颜色 | 代码 | 颜色 |
|---|---|---|---|
| 39 | 默认颜色 | ||
| 30 | 黑色 | 90 | 灰色 |
| 31 | 红色 | 91 | 亮红色 |
| 32 | 绿色 | 92 | 亮绿色 |
| 33 | 黄色 | 93 | 亮黄色 |
| 34 | 蓝色 | 94 | 亮蓝色 |
| 35 | 品红 | 95 | 亮品红色 |
| 36 | 青色 | 96 | 亮青色 |
| 37 | 白色 | 97 | 亮白色 |
字体背景色
每一个颜色都和上面相同,只是他们将作为背景色使用
| 代码 | 颜色 | 代码 | 颜色 |
|---|---|---|---|
| 49 | 默认颜色 | ||
| 40 | 黑色 | 100 | 灰色 |
| 41 | 红色 | 101 | 亮红色 |
| 42 | 绿色 | 102 | 亮绿色 |
| 43 | 黄色 | 103 | 亮黄色 |
| 44 | 蓝色 | 104 | 亮蓝色 |
| 45 | 品红 | 105 | 亮品红色 |
| 46 | 青色 | 106 | 亮青色 |
| 47 | 白色 | 107 | 亮白色 |
修改文件目录颜色
想在使用ls命令后使各种不同类型文件显示不同颜色,参考dircolors命令
OSC序列
OSC(Operating System Command)是一类用于执行操作系统级别命令的控制序列,通常用来设置终端标题,或与系统剪贴板进行交互等。OSC和CSI都是ANSI转义序列的一部分,其中CSI是C1控制字符集的一部分,而OSC是独立的多字符集合,不属于C1控制字符集
与CSI字符序列语法类似,OSC序列也是以ESC开头,随后,OSC序列后紧接一个],后接一个数字标识符,然后是一个命令或参数,最后以\a(BEL)或\e\(ESC+\)结尾,完整的OSC语法为:
\e]函数标识值;参数1;参数2;参数3…\a
- \e]是OSC控制序列的引导头
- 函数值功能参考下表
- \a 标识控制序列结束
OSC函数值
OSC字符序列也可以修改终端的文本颜色,背景色等样式,与CSI不同的是,OSC字符序列控制的是全局的终端样式,而CSI序列只修改跟随在CSI后的文本样式,而不会修改已经输出完毕的文本样式。但OSC在一些终端中(尤其远程终端中)只支持修改终端窗口的标题等,而不支持修改光标、文本颜色等样式
| 值 | 说明 |
|---|---|
| 0 | 更改窗口标题和标签栏标题 |
| 1 | 设置终端窗口的图标名 |
| 2 | 仅更改窗口标题 |
| 10 | 更改字体颜色(前景色) |
| 11 | 更改背景色 |
| 12 | 更改光标颜色 |
| 52 | 将文本写入剪贴板 |
| 104 | 重置所有颜色 |
修改命令提示符
默认情况下的命令提示符通常为[用户名@主机名 当前目录]主提示符(不同Linux发行版可能有所不同),如:[root@localhost etc]#,该默认值由系统定义的变量PS1决定,可通过echo $PS1 查看当前配置,也可以通过修改PS1变量自定义命令提示符,如:
通过修改PS1变量自定义的命令提示符,只在本次登录有效,系统重启后将失效,需要永久修改命令提示符,可以将上述语句写入配置文件/etc/bashrc中,若只想修改某个用户的终端,可以修改该用户家目录下的.bashrc配置文件中的PS1变量,修改完后可以使用source 文件名命令重新加载配置文件,使配置立即生效
修改命令提示符文本颜色
修改命令提示符文本颜色时,PS1变量值中的CSI语法需要使用[ ]进行包裹,并且”[ ]”需要使用转义字符进行转义,避免bash解析其中的语法,即语法为:
\[\e[颜色码m\]
以下是自定义命令提示符时常用的转义字符:
| 转义符 | 作用 |
|---|---|
| \u | 显示当前用户名 |
| \h | 显示简写主机名(不包含域名,该值来自/etc/hostname文件) |
| \H | 显示完整的主机名(通常包括域名) |
| \w | 显示当前所在路径的完整名称 |
| \W | 显示当前所在目录(路径的最后一个路径段) |
| \# | 显示本次会话已经执行的命令个数 |
| \$ | 显示命令主提示符,root用户提示符为”#”,普通用户为”$” |
| \d | 显示当前系统日期,格式为”星期 月 日” |
| \t | 显示24小时制时间,格式为”HH:MM:SS” |
| \T | 显示12小时制时间,格式为”HH:MM:SS” |
| \A | 显示24小时制时间,格式为”HH:MM” |
| \n | 换行符 |
| \[ 和 \] | 用于定义非打印字符的开始和结束(主要用于设置颜色,避免光标定位错误) |
终端标题
虽然PS1主要用于控制终端的命令提示符,但我们可以在PS1中嵌入OSC转义序列来控制终端的标题。与CSI类似,PS1变量值中的OSC序列也需要使用[ ]进行包裹,并且”[ ]”需要使用转义字符进行转义,避免bash解析其中的语法
本地终端登录前的欢迎信息
需要修改本地终端登录时显示的信息,可修改配置文件/etc/issue,配置文件中可使用的转义字符:
| 转义符 | 作用 |
|---|---|
| \d | 显示当前系统日期 |
| \t | 显示当前系统时间 |
| \s | 显示操作系统名称 |
| \l | 显示登录的终端号 |
| \m | 显示硬件架构信息,如i386等 |
| \n | 显示主机名 |
| \o | 显示域名 |
| \r | 显示内核版本 |
| \u | 显示当前用户登录的序列号 |
远程终端登录前的欢迎信息
修改远程终端登录时显示的信息,可修改配置文件/etc/issue.net,该文件不支持上述本地终端登录可用的转义字符,需要显示此欢迎信息,需要在配置文件/etc/ssh/sshd_config中加入Banner /etc/issue.net配置内容(需要重启生效)
# no default banner path
#Banner none
Banner /etc/issue.net
# Accept locale-related environment variables
终端登录成功后的提示信息
配置文件位于/etc/motd(Message of the Day文件),用于在远程和本地终端登录成功后显示提示信息,文件通常默认为空
在ubuntu中,登录提示文本MOTD通常是动态生成的,配置文件位于/etc/update-motd.d/中,包含一系列脚本,这些脚本会生成系统信息(如负载、内存使用等)并在登录时显示,脚本名前的数字表示脚本执行顺序,相同数字的脚本会按照脚本名字母顺序依次执行,执行顺序也决定了这些文本的显示顺序
#!/bin/sh
echo "欢迎使用shiwivi的 Ubuntu 服务器!"
3. 给脚本添加可执行权限
sudo chmod +x /etc/update-motd.d/99-custom
如果不想显示某个脚本的内容,可以通过修改文件名(例如在文件名中添加 .disabled)来禁用特定脚本,或者修改脚本中的输出语句
tput 终端控制标准化接口
介绍
Terminfo数据库
Terminfo数据库是Unix/Linux 系统中用于描述终端能力的标准化数据库,为各种终端提供统一的描述方式,将终端功能映射为标准名称,使应用程序无需关心具体终端差异即可用统一接口(tput)控制终端,这种设计使得Unix/Linux系统能够支持数千种不同的终端类型
标准 Terminfo 数据库通常位于以下位置:
- /usr/share/terminfo/
- /lib/terminfo/
这些目录中可能包含上百种不同的终端配置,它们根据终端名首字母被整理到了1-9a-Z不同目录下,如:/usr/share/terminfo/x/目录下包含了xterm等常用X window相关终端的配置,每个终端类型在 Terminfo 数据库中都有一个独立的编译文件,该编译文件保存了终端支持的行数、列数、颜色、控制序列等终端属性
tput命令工具
tput是一个用于终端控制的工具,作为terminfo数据库的前端,它能根据terminfo数据库提供一种标准化的方式来查询和修改终端的行为,tput抽象了不同终端之间的差异,为开发者提供了统一的控制接口
调用tput命令时,tput会首先检查TERM环境变量来确定当前终端类型,然后从terminfo数据库中查找对应的终端配置。当执行tput命令时,它会将用户请求的能力名称(如setaf表示设置前景色)转换为该终端类型实际支持的控制序列,tput将转换后的控制序列输出到标准输出,这些序列会被终端解释并执行相应的操作
与CSI控制序列的区别
CSI控制序列是直接将控制字符包含在输出的字符串中,字节流不经任何处理直接交由终端处理,由终端内置解析器负责实时解释执行。CSI控制序列有以下特点:
- 控制序列包含在输出序列中,简单高效,适合快速输出
- 同一段控制序列,不同终端的解析可能不同,行为不一致,甚至可能出现因为终端不支持而出现乱码等情况。
- CSI序列可能会被滥用于终端注入攻击
tput工作时,是先读取TERM环境变量确定终端类型,然后根据/usr/share/terminfo目录对应终端的配置编译文件,将终端控制请求转换为目标终端的专用序列,以达到动态翻译的效果。它有以下特点:
- 控制序列动态生成,需要tput程序介入处理
- 自动处理不同终端的实现差异,以保证行为一致,当某一个控制效果终端不支持时,tput会在序列生成阶段,回退到默认样式或终止操作,它能在跨平台脚本中提供更健壮的功能
- 没有CSI注入风险
tput命令
tput [选项] [terminfo功能名称] [参数]
- -T终端类型:手动指定一个终端类型用于查阅或操作,默认情况下tput会从TERM环境变量获取当前终端类型
- -V 查看当前版本
- -S >>标准输入:指定多个终端功能,此时需要从标准输入指定这些功能,而不再从命令行中指定,每行只能指定一个终端功能
基本terminfo功能
- tput init 初始化终端,重新加载终端的配置信息,常用于终端设置被修改时,恢复终端的默认配置
- tput clear 清空屏幕,将光标移动到左上角,在多数系统中,clear命令会在底层调用tput clear
- tput reset 重置终端,清空屏幕,并且重置终端的光标位置、回显位置(echo、print等命令输出位置)、键盘映射等配置,常用于终端出现严重异常,恢复终端。在部分终端中,该命令会清空滚动缓冲区,即清空终端的历史命令输出内容
- tput longname 输出终端的完整名称
颜色控制
常用终端类型xterm通常只支持8种(0-7颜色值)ANSI标准颜色(可以通过tput colors查看),如果需要使用更多颜色,可以修改终端类型为TERM=xterm-256color,以支持256种颜色
- tput colors 查看当前终端支持的颜色数量
- tput setaf 颜色值N设置终端前景色
- tput setab 颜色值N设置终端背景色
- tput op重置前景色和背景色为默认
- tput sgr0重置所有文字样式和颜色为默认
部分常用颜色值
| 编号 | 颜色 | 编号 | 颜色 |
|---|---|---|---|
| 0 | 黑色 | 8 | 灰色 |
| 1 | 红色 | 9 | 亮红色 |
| 2 | 绿色 | 10 | 亮绿色 |
| 3 | 黄色 | 11 | 亮黄色 |
| 4 | 蓝色 | 12 | 亮蓝色 |
| 5 | 品红 | 13 | 亮品红色 |
| 6 | 青色 | 14 | 亮青色 |
| 7 | 白色 | 15 | 亮白色 |
文字样式控制
| 功能名 | 作用 | 功能名 | 作用 |
|---|---|---|---|
| bold | 加粗 | dim | 淡化 |
| smul | 开启下划线 | rmul | 关闭下划线 |
| rev | 反显(前后景色交换) | blink | 闪烁 |
| smso | 开启”突出模式” | rmso | 关闭”突出模式” |
| invis | 隐藏文字 | sgr0 | 重置所有样式和颜色 |
光标控制
注意,指定光标(行列)位置时,从0开始计算位置
- tput cols 获取终端列数(宽度)
- tput lines 获取终端行数(高度)
- tput home将光标移动到左上角(0,0)
- tput cup 行 列将光标移到指定行列,行列从0开始计数
- tput hpa 列将光标移动到指定列
- tput vpa 行将光标移动到到指定行
- tput ll移动光标到最后一行第一列
- tput sc保存当前光标位置(部分终端可能不支持)
- tput rc恢复保存的终端位置(部分终端可能不支持)
- tput civis隐藏光标
- tput cnorm恢复光标显示
模拟一个进度条
#!/bin/bash
#初始化终端
tput civis #隐藏光标
tput sc #保存光标位置
#配置颜色
red_color=$(tput setaf 1)
blue_color=$(tput setaf 4)
reset=$(tput sgr0)
#模拟进度条
for i in {0..100};do
#计算进度条的"#"和空白部分,并缩减进度条长度到50字符
filled=$((i/2))
empty=$((50-filled))
#下述命令printf "%0.s#" $(seq 1 $filled)中
#由于%0.s#部分限制参数输出宽度为0
#因此不会输出$(seq 1 $filled)的内容
#只会输出一个格式字符串中指定的"#"
#$(seq 1 $filled)会被展开
#命令解析为printf "%0.s#" 1 2 3...
#所有参数共用格式字符串"%0.s#",每有一个参数,就会输出一个"#"
#因此$(seq 1 $filled)输出内容并不重要,它们只负责让printf输出一个#
#$(seq 1 $filled)只用来指定重复输出#的个数
#如果输出数量一定,printf "%0.s#" {1..5}也是类似的作用
bar=$(printf "%0.s#" $(seq 1 $filled)) #输出#
space=$(printf "%0.s " $(seq 1 $empty))#输出空白符
tput rc #每次都从原光标位置开始打印进度条,以覆盖上次的进度条
echo -ne "${blue_color}[${bar}${space}]${reset} ${red_color}${i}%${reset}"
sleep 0.05
done
#结束打印
echo #输出换行
tput cnorm #恢复光标显示
文字自动居中
cols=$(tput cols)
msg="居中标题"
padding=$(( (cols - ${#msg}) / 2 ))
printf "%*s%s\n" "$padding" "" "$msg"
擦除行
- tput ed 擦除光标之后的所有行,仅保留光标之前的行
- tput el 擦除当前行光标之后到行末的内容
- tput el1 擦除当前行光标之前到行开头间的内容
- tput el2 擦除整行
插入/删除行与列
- tput il 插入一行,重排 UI
- tput dl 删除一行,重排 UI
- tput ich 在当前位置插入字符
- tput dch 删除当前位置字符
切换屏幕缓冲区
实现类似less、top、vim等命令,独占整个屏幕,且命令结束返回原屏幕的效果
- tput smcup切换到新屏幕
- tput rmcup切换回原屏幕