学习 Bash,首先需要理解 Shell 是什么。Shell 伴随着 Unix 系统的诞生而诞生。Shell 这个单词的原意是“外壳”,跟 kernel(内核)相对应,比喻内核外面的一层,即用户跟内核交互的对话界面。
具体来说,Shell 这个词有多种含义。
首先,Shell 是一个程序,提供一个与用户对话的环境。这个环境只有一个命令提示符,让用户从键盘输入命令,所以又称为命令行环境(command line interface,简写为 CLI)。Shell 接收到用户输入的命令,将命令送入操作系统执行,并将结果返回给用户。
其次,Shell 是一个命令解释器,解释用户输入的命令。它支持变量、条件判断、循环操作等语法,所以用户可以用 Shell 命令写出各种小程序,又称为脚本(script)。这些脚本都通过 Shell 的解释执行,而不通过编译。
最后,Shell 是一个工具箱,提供了各种小工具,供用户方便地使用操作系统的功能。
Shell 有很多种,只要能给用户提供命令行环境的程序,都可以看作是 Shell。
1 | # 查看当前的 Linux 系统安装的所有Shell |
Bash 是 Unix 系统和 Linux 系统的一种 Shell(命令行环境),是目前绝大多数 Linux 发行版的默认 Shell。
1 | # 查看当前设备的默认 Shell |
当前正在使用的Shell不一定是默认Shell。一般来说,ps
命令结果的倒数第二行是当前使用的Shell
1 | |root@m01 ~|$ ps |
用户可以通过bash
命令的--version
参数或者环境变量$BASH_VERSION
,查看本机的 Bash 版本。
如果是不带有图形环境的 Linux 系统(比如专用于服务器的系统),启动后就直接是命令行环境。
不过,现在大部分的Linux 发行版都是图形环境。用户登录系统后,自动进入图形环境,需要自己启动终端模拟器,才能进入命令行环境。
所谓“终端模拟器”(terminal emulator)就是一个模拟命令行窗口的程序,让用户在一个窗口中使用命令行环境,并且提供各种附加功能,比如调整颜色、字体大小、行距等等。
不同 Linux 发行版(准确地说是不同的桌面环境)带有的终端程序是不一样的,比如 KDE 桌面环境的终端程序是 konsole,Gnome 桌面环境的终端程序是 gnome-terminal,用户也可以安装第三方的终端程序。所有终端程序,尽管名字不同,基本功能都是一样的,就是让用户可以进入命令行环境,使用 Shell。
进入命令行环境以后,用户会看到 Shell 的提示符。提示符往往是一串前缀,最后以一个美元符号$
结尾,用户可以在这个符号后面输入各种命令。
1 | [user@hostname] $ |
上面例子中,完整的提示符是[user@hostname] $
,其中前缀是用户名(user
)加上@
,再加主机名(hostname
)。比如,用户名是bill
,主机名是home-machine
,前缀就是bill@home-machine
。
注意:root用户的提示符以 #
结尾,用来提醒用户,现在具有根权限,不要出现误操作。这个符号是可以自己定义的,详见《命令提示符》一章。
进入命令行环境以后,一般就已经打开 Bash 了。如果你的 Shell 不是 Bash,可以输入bash
命令启动 Bash。
1 | $ bash |
退出 Bash 环境,可以使用exit
命令,也可以同时按下Ctrl + d
。
1 | $ exit |
Bash 提供很多快捷键,可以大大方便操作。下面是一些最常用的快捷键。
页面操作
Ctrl + L
:清除屏幕并将当前行移到页面顶部。Ctrl + C
:中止当前正在执行的命令。Ctrl + D
:关闭 Shell 会话。Shift + PageUp
:向上滚动。Shift + PageDown
:向下滚动。光标操作
ctrl + a
:光标移动到行首ctrl + e
:光标移动到行尾Ctrl + u
:从光标位置删除到行首。Ctrl + k
:从光标位置删除到行尾。Ctrl + w
:删除光标位置前一个单词。Alt + f
:移动到当前单词的词尾。Alt + b
:移动到当前单词的词首。Alt + .
:插入上一个命令的最后一个词。对于很长的文件路径,有时会非常方便编辑操作
Ctrl + k
:剪切光标位置到行尾的文本。Ctrl + u
:剪切光标位置到行首的文本。Ctrl + y
:在光标位置粘贴文本。除了上面的快捷键,Bash 还具有自动补全功能。命令输入到一半的时候,可以按下 Tab 键,Bash 会自动完成剩下的部分。
命令行环境中,主要通过使用 Shell 命令,进行各种操作。Shell 命令基本都是下面的格式。
1 | $ command [ arg1 ... argN] |
上面代码中,command
是具体的命令或者一个可执行文件,arg1 ... argN
是传递给命令的参数,它们是可选的。
Bash 使用空格(或 Tab 键)区分不同的参数。如果参数之间有多个空格,Bash 会自动忽略多余的空格。
参数形式
有些参数是命令的配置项,这些配置项一般都以一个连词线开头,比如ls
命令的-l
。
同一个配置项往往有长和短两种形式,比如-l
是短形式,--list
是长形式,它们的作用完全相同。短形式便于手动输入,长形式一般用在脚本之中,可读性更好,利于解释自身的含义。
1 | # 短形式 |
多行命令
Bash 单个命令一般都是一行,用户按下回车键,就开始执行。有些命令比较长,写成多行会有利于阅读和编辑,这时可以在每一行的结尾加上反斜杠,Bash 就会将下一行跟当前行放在一起解释。
1 | $ echo foo bar |
命令组合符
正常情况下,分号(;
)是命令的结束符,使得一行可以放置多个命令,上一个命令执行结束后,再执行第二个命令。
同时Bash也提供了两个命令组合符&&
和||
,允许更好地控制多个命令之间的继发关系。
;
1 | # 使用分号时,第二个命令总是接着第一个命令执行,不管第一个命令执行成功或失败。 |
&&
1 | # 使用 && 时,如果 Command1 命令运行成功,则继续运行 Command2 命令 |
||
1 | # 使用 || 时,如果 Command1 命令运行失败,则继续运行 Command2 命令 |
Bash 会保留用户的操作历史,即用户输入的每一条命令都会记录。退出当前 Shell 的时候,Bash 会将用户在当前 Shell 的操作历史写入~/.bash_history
文件,该文件默认储存500个操作。环境变量HISTFILE
总是指向这个文件。
HISTTIMEFORMAT
通过定制环境变量HISTTIMEFORMAT
,可以显示每个操作的时间。
1 | $ export HISTTIMEFORMAT='%F %T ' # `%F`相当于`%Y - %m - %d`,`%T`相当于` %H : %M : %S`。 |
HISTSIZE
环境变量HISTSIZE
设置保存历史操作的数量。
1 | $ export HISTSIZE=10000 # 设置保存过去10000条操作历史。 |
如果不希望保存本次操作的历史,可以设置HISTSIZE
等于0。如果HISTSIZE=0
写入用户主目录的~/.bashrc
文件,那么就不会保留该用户的操作历史。如果写入/etc/profile
,整个系统都不会保留操作历史。
HISTIGNORE
环境变量HISTIGNORE
可以设置哪些命令不写入操作历史。
1 | export HISTIGNORE='pwd:ls:exit' # 设置`pwd`、`ls`、`exit`这三个命令不写入操作历史。 |
history
命令会输出.bash_history
文件的全部内容。用户可以看到最近执行过的所有命令,每条命令之前都有行号。越近的命令,排在越后面。
如果想搜索某个以前执行的命令,可以配合grep
命令搜索操作历史。
1 | $ history | grep /usr/bin # 返回`.bash_history`文件里面,那些包含`/usr/bin`的命令。 |
操作历史的每一条记录都有编号。可以用!n
执行该命令。 !!
代表执行上一个命令。
1 | # 指定行号为8的命令 |
history
命令的-c
参数可以清除操作历史。
1 | $ history -c |
输入命令时,按下Ctrl + r
快捷键,就可以搜索操作历史,选择以前执行过的命令。这时键入命令的开头部分,Shell 就会自动在历史文件中,查询并显示最近一条匹配的结果,这时按下回车键,就会执行那条命令。
另外,!string
表示找出操作历史之中,最近的那一条以string
开头的命令并执行。Bash 会先输出那一条命令,然后直接执行。注意,!string
语法只会匹配命令,不会匹配参数。
Bash 本身内置了很多命令,同时也可以执行外部程序。通过type
命令可以判断命令的来源。
1 | $ type echo |
使用type
命令的-a
参数,可以查看一个命令的所有定义
1 | $ type -a echo |
使用type
命令的-t
参数,可以返回一个命令的类型:别名(alias),关键词(keyword),函数(function),内置命令(builtin)和文件(file)。
1 | $ type -t bash |
echo
命令是Linux中最基本的命令,作用是在屏幕输出一行文本,可以将该命令的参数原样输出。
1 | $ echo hello world |
如果想要输出的是多行文本,即包括换行符。这时就需要把多行文本放在引号里面。
-n
默认情况下,echo
输出的文本末尾会有一个回车符。-n
参数可以取消末尾的回车符,使得下一个提示符紧跟在输出内容的后面。
1 | # -n 参数可以让两个 echo 命令的输出连在一起,出现在同一行。 |
-e
-e
参数会解释引号(双引号和单引号)里面的特殊字符(比如换行符\n
)。如果不使用-e
参数,即默认情况下,引号会让特殊字符变成普通字符,echo
不解释它们,原样输出。
1 | $ echo "Hello\nWorld" |