一些与 Bash 相关的内容,如命令执行顺序、配置文件、通配符、元字符及转义字符等。
命令执行顺序
Shell 一般会按照 alias
keyword
function
built-in
$PATH
的顺序进行搜索。
在执行完命令之后会保存在一个 hash 表中,下次直接通过 hash 查找,如果将一个命令删除可能会出现 No such file or directory
的错误;可以通过 set -h
启用 hash 功能,set +h
禁用。
可通过 hash
查看当前列表,hash -d command
删除该记录,hash -r
删除所有记录,重新搜索。
通过 hash
命令查看时,其第一列为使用的次数,注意不会缓存 function
、built-in
以及部分 alias
;注意,不会缓存包含绝对路径的 alias
命令。
可以通过
alias cmd
查看定义的 alias ,一般通过alias cmd='xxx'
定义别名,unalias cmd
删除别名。
常见操作可以参考如下:
----- 可以查看该命令的所有类型
$ type -a cmd
----- 查看执行时的类型
$ type cmd
----- 查看所有的built-in命令
$ enable
----- 禁用built-in的cmd命令
$ enable -n cmd
----- 启用built-in的命令
$ enable cmd
配置文件
Bash 的很多配置文件,要说清楚这些配置文件的区别,则首先要了解 login shell 和 no login shell 的区别。
- login shell 指的是完整的登录流程,需要输入用户名和密码,例如
tty1~tty6
等。 - no login shell,简单来说是 XWindow 登陆后又启动了多个终端,此时不需要输入密码。
Bash 配置文件包括全局配置文件和用户相关的局部配置文件。
全局变量
全局配置文件 /etc/profile
,在任何用户第一次登陆时 (或在切换用户时使用 -
参数) 都会读取该文件。
另外一个是 /etc/bashrc
,其中 Ubuntu 没有这个文件,与之对应的是 /etc/bash.bashrc
,会在 bash 执行时会读取此文件。
局部变量
在执行完全局变量后,执行用户指定的配置文件,依次检查 ~/.bash_profile
~/.bash_login
~/.profile
最先找到的直接执行,然后退出。
其中相关的配置文件有如下:
~/.bash_profile
Ubuntu 默认没有此文件,可新建,只有 Bash 是以 login 形式执行时,才会读取此文件,通常来说该配置文件还会配置成读取~/.bashrc
。~/.bash_login
若 bash 是以 login 方式执行时,读取~/.bash_profile
,若它不存在,则读取~/.bash_login
,若两者都不存在,读取~/.profile
。~/.profile
除了上述的配置文件执行方式外,在图形模式登录时,此文件被读取,即使存在~/.bash_profile
和~/.bash_login
。~/.bashrc
当 Bash 是以 non-login 形式执行时,读取此文件,若以 login 形式执行,则不会读取此文件,但是通常在上述的三个文件中会调用该文件。~/.bash_logout
注销时,且是 login 形式,此文件才会读取。也就是说,在文本模式注销时,此文件会被读取,图形模式注销时,此文件不会被读取。
读取顺序
login shell 和 non-login shell 读取的配置文件数据并不一样。
----- login shell会读配置文件,后面的三个读取一个文件后就会退出
/etc/profile ~/.bash_profile或~/.bash_login或~/.profile
----- non-login shell会读配置文件
~/.bashrc
通配符、元字符及转义字符
介绍一些与之相关的概念。
通配符
通配符是由 shell 处理的,在遇到了通配符时,shell 会将其当作路径或文件名去在磁盘上搜寻可能的匹配:若符合要求的匹配存在,则进行代换 (路径扩展);否则就将该通配符作为一个普通字符传递给 “命令”,然后再由命令进行处理。
总之,通配符实际上就是一种 shell 实现的路径扩展功能,在通配符被处理后,shell 会先完成该命令的重组,然后再继续处理重组后的命令,直至执行该命令。
常见示例如下:
* 匹配0或多个字符,a*b: acb, a123db
? 匹配任意单一字符,a?b: acb, a1b
[list] 匹配list中的任意单一字符,a[xyz]b: axb, ayb, azb
[!list] 匹配除list中的任意单一字符,a[!0-9]b: aab, acb, a-b
[c1-c2] 匹配c1到c2中的任意单一字符,a[0-9]b: a0b, a1b
{str1, str2} 匹配str1或str2中的任意字符串,a{ab, cd}b: aabb, acdb
元字符
Shell 除了有通配符之外,由 shell 负责预先先解析后,将处理结果传给命令行之外,shell 还有一系列自己的其他特殊字符。
IFS 由 space 或 tab 或 enter 三者之一组成(我们常用 space )。
CR 由 enter 产生。
= 设定变量。
$ 作变量或运算替换(请不要与 shell prompt 搞混了)。
> 重导向 stdout。
< 重导向 stdin。
| 命令管线。
& 重导向 file descriptor ,或将命令置于背境执行。
( ) 将其内的命令置于 nested subshell 执行,或用于运算或命令替换。
{ } 将其内的命令置于 non-named function 中执行,或用在变量替换的界定范围。
; 在前一个命令结束时,而忽略其返回值,继续执行下一个命令。
&& 在前一个命令结束时,若返回值为 true,继续执行下一个命令。
|| 在前一个命令结束时,若返回值为 false,继续执行下一个命令。
! 执行 history 列表中的命令。
转义字符
有时候,我们想让通配符,或者元字符变成普通字符,不需要使用它。那么这里我们就需要用到转义符了。shell提供转义符有三种。
'' 硬转义,其内部所有的shell 元字符、通配符都会被关掉。注意,硬转义中不允许出现'(单引号)。
"" 软转义,其内部只允许出现特定的shell 元字符:$用于参数代换 `用于命令代替 \用于转义。
\ 转义,去除其后紧跟的元字符或通配符的特殊意义。
Bash 历史
输入命令时 Bash 将其保存在内存中,其大小由 HISTSIZE
决定,在 Bash 退出时将 HISTFILESIZE
的最近的命令保存在 HISTFILE
中,在 ~/.bash_profile
中可以修改设置。
在启动 Bash 时会从 HISTFILE
读入 HISTSIZE
大小的命令行,通常在写入历史文件时使用的是覆盖方式,如果需要以追加方式添加可以 shopt -s listappend
。
----- 显示命令执行的时间戳,之前的命令不会
$ export HISTTIMEFORMAT='%F %T '
----- 剔除连续重复的条目,erasedups剔除整个历史中重复的条目,ignorespace在不想被记住的命令前加上空格
$ export HISTCONTROL ignoredups
----- 忽略特定的命令
$ export HISTIGNORE="pwd:ls:ls -ltr:"
可以通过 Ctrl-R
和 Ctrl-S
来对历史进行搜索,通过 Ctrl-G
可以复位,更多快捷键可参考 Bash Reference Manual 文档。
history 显示所有的历史命令,包括序号。
history N 显示最近的N条历史命令。
history -c 清楚所有的历史命令。
history -d N 清除第N条历史命令。
!string 用来查找最近的以string开头历史命令。
!?string 用来查找最近含有string的命令,不是严格以string开头历史命令。
^string1^string2^ 将上一条命令中的string1替换为string2。
!number 执行历史中的第number条命令。
!! 执行上一条命令。
!-number 执行最近的第N条命令。
!$ <<==>> !!:$ 获得上一条命令的最后一个参数。
!^ <<==>> !!:^ 获得上一条命令的第一个参数。
!cp:2 查找最近以cp开头的命令,并取得第二个参数。
示例:
$ echo a b c d e
a b c d e
$ echo !!:2
b