第三章 使用 shell
本章介绍的 Linux shell 称为 Bash shell,其全称为 Bourne Again shell。还有其他的 shell,例如在 BSD UNIX 用户中流行的 C shell (csh) ,以及在 UNIX System V 用户中非常流行的 Korn shel (ksh) ,Ubuntu 默认启动 Dash shell (速度比 Bash快) ,还有 Tcsh shell (一种改进的 C shell) 和 Ash shell (与 Bourne shell 非常相似)
3.1 shell 和 Terminal 窗口
- 使用 Terminal 窗口
通过运行的 GUI,可以打开一个终端仿真程序 (有时也称为 Terminal 窗口) ,从而启动一个 shell
大部分系统通过 Ctrl+Shift+T 快捷键打开,Fedora 可在程序中寻找,或者按 alt+F2 后输入 gnome-terminal
- 使用虚拟控制台
大多数有 GUI 的 Linux 系统在启动时通常会运行多个虚拟控制台,虚拟控制台除了可以打开 GUI 之外,还可以打开多个 shell 会话
通过 Ctrl+Shift+F1~F6 可切换虚拟控制台。以 Fedora 为例,tty1 为 gdm (登录屏幕) ,tty2 为第一个桌面, tty3 为第二个桌面 (纯文本) ,以此类推
- 命令提示符
对于普通用户来说,默认的提示符是一个简单的美元符号
$
对于 root 用户来说,默认的提示符是一个英镑符号 (有时也称为 number sign 或 hash tag)
#
生动形象得说明了美国本源在英国
3.2 选择 shell
使用 who
命令即可显示当前登录用户名,登录的虚拟控制台以及登录的时间
使用 grep username /etc/passwd
命令,在输出的最后可看到默认使用的 shell
可以通过输入命令以切换 shell,例如 ksh、tcsh、csh、sh、dash 或其他 shell (假设已经安装了这些 shell)
学习 Bash shell 不仅是因为它是大多数安装中默认的 shell,也是因为它是大多数 Linux 认证考试中所使用的 shell
3.3 运行命令
虽然只需要通过输入命令名称就可以运行许多命令,但更常见的做法是在命令之后输入 more,从而改变其行为。在命令之后输入的字符和单词成为选项和参数
3.3.1 了解命令语法
- 大多数命令都有一个或多个用来改变命令行为的选项
一般选项由单个字母构成,并在前面添加一个连字符 -
,然而为了每次使用多个选项,也可以将多个但字母选项组合在一起,或者在每个选项前面都使用一个连字符
一些命令的选项由一个完整的单词组成,一般需要在单词前使用双连字符 --
。例如,为了使用 help
这个选项,需要输入 --help
,如果是 -help
将被解释为 -h
、-e
、-l
、-p
这四个选项。尽管有些命令不遵守双连字符约定,但大多数命令还是要在单词选项前使用双连字符
- 此外,大多数命令还可在输入某些选项后或者整个命令行结尾处接受参数
参数是一个额外的信息块,比如文件名、目录、用户名、设备或其他用来告诉命令如何运行的信息。通常,在命令行中可以使用任意数量的参数,只要数量不超过单个命令行所允许的总字母数即可
有时,一个参数与一个选项相关联,此时参数必须跟在选项之后。如果使用的是单字母选项,那么参数通常在一个空格后。而对于全单词选项,参数跟在一个等号 =
之后
例如
tar -cvf backup.tar /home/yexca
选项的含义是创建 (c) 一个名为 backup.tar 的文件 (f) ,其中包含 /home/yexca 目录的全部文件,并且在备份文件创建完毕 (v) 后显示详细信息。因为 backup.tar 是 f 选项的一个参数,所以 backup.tar 必须跟在选项之后
ls --hide=Desktop
–hide 选项告诉 ls 命令不要显示名为 Desktop 的文件或目录,注意选项与参数之间没有空格
- 还可以尝试其他的命令
uname
命令显示正在运行的系统类型,添加了 -a
选项后还可以查看主机名及内核版本
当登录到一个 Linux 系统时,Linux 会认定您具有特定的身份,其中包括用户名、组名、用户 ID 和组 ID。此外,Linux 还会跟踪登录会话,从而了解登录的时间、空闲的时间以及登录的地点等。可通过 id
命令查看身份相关信息
启用了 SELinux (Security Enhanced Linux) 的 Linux 发行版本都在
id
输出的末尾显示了额外信息,例如context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
SELinux 提供了一种可以紧紧锁定 Linux 系统安全性的方法
通过 who -uH
可添加关于空闲时间和进程 ID 信息 (u) ,以及要求打印标头 (H)
空闲 (IDLE) 表示没有任何命令输入的情况下 shell 保持打开状态的时间长度。进程号 (PID) 表示用户登录 shell 的进程 ID。而备注 (COMMENT) 则表示用户用来进行登录操作的远程计算机名称 (前提是用户使用了网络上的另一台计算机进行登录) ,或者本地 X Display 的名称 (前提是用户正在使用一个 Terminal 窗口) ,比如 :0.0
3.3.2 查找命令
为了找到所输入的命令,shell 在所谓的路径中进行查找,对于不在路径中的命令,可通过输入命令位置的完整标识进行运行
通过 echo $PATH
以查看 shell 的环境变量 PATH
参考:Linux 下 bin 目录 – yexca|Hiyoung‘Blog
与其他一些操作系统不同的是,默认情况下,在搜索路径之前,Linux 并不会为了查找可执行文件检查当前目录,而是马上开始搜索路径,只有在可执行文件位于 PATH 环境变量或者给定了可执行文件的绝对地址或相对地址时,才会运行当前目录的可执行文件
并不是所有的命令都位于 PATH 变量的目录中,一些命令内置于 shell,通过创建用来定义任何命令的别名以及选项,可以重写另外一些命令。下面是 shell 检查输入命令的顺序
- 别名。由
alias
命令设置的名称,可输入此命令以查看创建的别名 - shell 保留字。shell 保留了一些单词用作特殊用途
- 函数。一组能够在当前 shell 中共同运行的命令
- 内置命令。内置于 shell 中的命令,在文件系统中没有命令的表现形式,例如 cd、echo、exit、pwd、history (查看以前运行的命令列表)、fg (将一个后台运行的命令带入前台) 、set (设置 shell 选项) 和 type (显示命令的位置)
- 文件系统命令。存储在计算机文件系统中的命令 ( 这些命令由 PATH 变量值表示)
为了知道命令的出处,可以使用 type
或者 which
命令,通过使用 type -a
可显示命令的所有已知位置
如果一些命令不在 PATH 变量中,可使用 locate
命令尝试查找该命令,通过使用 locate
命令可以访问系统中任何可访问的部分
locate
命令会对整个文件系统进行查找,而不仅仅是在包含了命令的目录中查找,如果没有找到最近添加的文件,可以 root 用户身份运行 updatedb
以更新 locate 数据库
3.4 使用命令历史记录重复执行命令
重复执行那些冗长、复杂且易于输错的命令将可以避免很多问题的出现
3.4.1 命令行编辑
默认情况下,Bash shell 使用基于 Emacs 文本编辑器的命令行编辑。如果更喜欢使用 vi,可以将 set -o vi
添加到主目录的 .bashrc 文件中
- 用来导航命令行的按键
按键 | 全称 | 含义 |
---|---|---|
Ctrl+F | 向前一个字符 | 前进一个字符 |
Ctrl+B | 向后一个字符 | 后退一个字符 |
Alt+F | 向前一个单词 | 前进一个单词 |
Alt+B | 向后一个单词 | 后退一个单词 |
Ctrl+A | 命令行开头 | 转到当前命令行的开头 |
Ctrl+E | 命令行结尾 | 转到当前命令行的结尾 |
Ctrl+L | 清除屏幕 | 清除屏幕,并使光标停留在屏幕顶部 |
- 用来编辑命令行的按键
按键 | 全称 | 含义 |
---|---|---|
Ctrl+D | 删除当前字符 | 删除当前字符 |
Backspace | 删除前一个字符 | 删除前一个字符 |
Ctrl+T | 调换字符 | 交换当前字符和前一个字符的位置 |
Alt+T | 调换单词 | 交换当前单词和前一个单词的位置 |
Alt+U | 大写单词 | 将当前单词改为大写 |
Alt+L | 小写单词 | 将当前单词改为小写 |
Alt+C | 首字母大写单词 | 把光标当前位置单词的头一个字母变为大写 |
Ctrl+V | 插入特殊字符 | 添加一个特殊字符,例如添加 Tab |
- 用来剪切和粘贴命令行中文本的按键
按键 | 全称 | 含义 |
---|---|---|
Ctrl+K | 剪切到行末 | 剪切光标后面的所有字符 |
Ctrl+U | 剪切到行首 | 剪切光标后面的所有字符 |
Ctrl+W | 剪切前一个单词 | 剪切位于当前光标之后的一个单词 |
Alt+D | 剪切后一个单词 | 剪切位于当前光标之前的一个单词 |
Ctrl+Y | 粘贴当前文本 | 粘贴最近剪切的文本 |
Alt+Y | 粘贴早期文本 | 转回到早期剪切的文本并粘贴 |
Ctrl+C | 删除整行 | 删除整个命令行 |
3.4.2 命令行补齐
为了减少按键,Bash shell 提供了多种不同的方法来补齐部分输入值。为了尝试补齐一个值,需要输入前几个字符并单击 Tab 键。下面是可以通过 Bash shell 部分输入的值:
- 命令、别名或函数。如果所输入的文本以常规字符开头,shell 将尝试使用命令、别名或者函数名来补齐该文本
- 变量。如果所输入的文本以美元符号
$
开头,那么 shell 将使用来自当前 shell 的一个变量来补齐文本 - 用户名。如果所输入的文本以波浪号
~
开头,shell 将使用一个用户名补齐文本。因此,~username 表示指定用户的主目录 - 主机名。如果所输入的文本以 at 符号
@
开头,shell 将使用来自/etc/hosts
文件中的一个主机名补齐文本
如果想要添加来自其他文件的主机名,只需要将 HOSTFILE 变量设置为该文件名,但该文件是与
/etc/hosts
相同的格式
如果所输入的字符串可以产生多种补齐结果,此时可以通过双击 TAB 键列出所有可能的结果
3.4.3 命令行重复执行
在输入完一行命令后,该命令行会保存到 shell 的历史命令列表中
通过 history
命令查看历史命令列表,或者添加数字参数以显示指定数量的最新命令
通过使用感叹号 !
以重复执行这些命令,此种方法将直接执行,没有再次确认的机会
- !n — 运行命令编号。例如
!255
将运行第 255 个命令 - !! — 运行前一个命令
- !?string? — 运行包含字符串的命令
除了直接运行 history 外,还可重复执行特定命令并进行编辑
按键 | 功能 | 描述 |
---|---|---|
箭头键或 Ctrl+P 与 Ctrl+N | 步骤 | 遍历历史命令列表的每一个命令行,直到找到所需的命令行 |
Ctrl+R | 反向增量搜索 | 按下后可输入一个搜索字符串,完成反向搜索。当输入字符串时,会出现可以运行或编辑的相匹配的命令行 |
Ctrl+S | 向前增量搜索 | 与上一个类似,不过是向前搜索。并不是所有情况都可用 |
Alt+P | 反向搜索 | 按下后可输入一个搜索字符串,完成反向搜索。输入字符串并单击 Enter 键后可看到该字符串的最新命令行 |
Alt+N | 向前搜索 | 与上一个类似,不过是向前搜索。并不是所有情况都可用 |
还可使用 fc
命令以使用历史命令列表。输入 fc
后跟着一个历史命令行编号或一个范围 (例如 fc 233 255
) ,将在文本编辑器中打开这些命令 (默认为 vi) ,关闭编辑器后命令将 (逐个) 运行
关闭 shell 后,历史命令列表将保存到主目录的 .bash_history 文件中,默认最多保存1000条
如果不想保存历史命令列表,就不要正常退出 shell,可通过
kill -9 PID
关闭 shell 会话以不保存历史命令将变量 HISTFILE 设置为 /dev/null 或保持 HISTSIZE 为空都是没用的,只要 shell 正常退出,就会永久保存 shell 历史
3.5 连接和拓展命令
shell 真正强大的功能在于能将命令的输入和输出重定向到其他命令或文件中,反之亦然
为了将命令串在一起,shell 使用了元字符 (metacharacter) 。元字符是对 shell 有特殊含义的输入字符,用于连接请求或拓展请求
元字符包括管道字符 |
、与号 &
、分号 ;
、右括号 )
、左括号 (
、小于号 <
和大于号 >
3.5.1 命令之间的管道
管道字符 |
将一个命令的输出连接到另一个命令的输入,例如
cat /etc/passwd | sort | less
该命令列出 /etc/passwd 文件内容。输出到 sort 命令以对内容排序,最后发送到 less 以显示输出
3.5.2 连续命令
使用分号 ;
将多个命令隔开可在同一命令行输入多条命令以执行连续的命令,例如
date ; troff -me VertLargeDocument | lpr ; date
对一个很大的文档格式化,并显示格式化所需的时间
3.5.3 后台命令
一些命令可能需要花费很长时间才能完成,可使用与号 &
让命令在后台运行,例如
troff -me VertLargeDocument | lpr &
在进程结束之前不要关闭 shell 或杀死该进程,否则进程将终止
3.5.4 拓展命令
通过命令替换,可以使一条命令的标准输出变为另一条命令的一个参数
命令替换的两种形式是 $(command)
和 command
(注意是反引号)
两种形式中的命令可以包括选项、元字符和参数,例如
vi $(find /home | grep xyzzy)
在 vi 命令运行之前完成了命令替换。首先 find 命令从 /home 目录寻找所有文件于目录,然后将输出连接到 grep 命令,将文件名中不包含 xyzzy 的过滤掉,最后使用 vi 打开所有文件进行编辑 (每次打开一个文件)
注意:不要从根文件系统开始使用 grep,否则将匹配并尝试编辑几千个文件
3.5.5 扩展算术表达式
有时可能需要将算术结果传递给一条命令。通过 S[expression]
或者 S(expression)
,例如
echo "I am $[2022-1957] years old"
输出为 I am 65 years old
echo "There are S(ls | wc -w) files in this directory"
该命令列出当前目录内容 (ls) 并运行了单词计数命令,计算出找到的文件数量 (wc -w) ,然后输出
3.5.6 扩展变量
使用美元符号 $
对 shell 中用来存储信息的变量进行拓展。当在命令行中扩展一个环境变量时,所打印的是变量的值,而不是变量名,例如
ls -l $BASH
打印 bash 命令的长列表 -rwxr-xr-x. 1 root root 1390064 1月 20 2022 /usr/bin/bash
3.6 使用 shell 变量
shell 本身使用变量存储了对用户的 shell 会话非常有用的信息。如果想要查看当前 shell 设置的所有变量,可以使用 set
命令
其中,本地变量的一个子集被称为环境变量,对任何通过当前 shell 打开的新 shell 都是可用的。可以使用 env
命令查看环境变量
除了所设置的变量之外,系统文件也会设置一些用来存储相关信息的变量,比如配置文件、邮箱以及路径目录的位置。此外,这些变量还可以存储关于 shell 提示符、历史命令列表的大小以及操作系统类型的相关值。如果想引用这些变量的值,需要在变量之前添加一个美元符号 $
当启动一个 shell 时,许多环境变量已经被设置了,下表为一些既可以在使用 Bash shell 时设置,又可以为了使用不同功能而设置的变量
变量 | 描述 |
---|---|
BASH | 包含了 Bash 命令的完整路径。其值通常为 /bin/bash |
BASH_VERSION | 表示当前 Bash 命令版本的一个数字 |
EUID | 表示当前用户有效的用户 ID 号。当启动 shell 时,根据 /etc/passwd 文件中的用户项进行赋值 |
FCEDIT | fc 命令用来编辑 history 命令的文本编辑器,默认为 vi |
HISTFILE | 历史命令文件的位置,通常位于 $HOME/bash_history |
HISTFILESIZE | 可以存储的历史命令条目的数量。当达到该数量时,最早的命令将被丢弃,默认为 1000 |
HISTCMD | 返回历史命令列表中当前命令的数量 |
HOME | 主目录 |
HOSTTYPE | 描述了 Linux 系统正在运行的计算机系统结构。对于 Intel 兼容的 PC,其值为 i386、i486 或 i386-Linux 类似的值。而对于 AMD 64 位计算机,其值为 x86_64 |
邮箱文件的位置,通常为 /var/spool/mail/$USER | |
OLDPWD | 修改当前工作目录之前的工作目录 |
OSTYPE | 用来识别当前操作系统。对于 Fedora,值为 Linux 或 Linux-gnu |
PATH | 值为冒号 : 分隔的目录列表,主要用来查找需要输入的命令 |
PPID | 当前 shell 的命令的进程 ID |
PROMPT_COMMAND | 可以将该变量设置为一个命令名,以便在每次 shell 提示符显示之前运行该命令 |
PS1 | 设置 shell 提示符的值。由时命令需要额外的提示符,可以使用变量 PS2、PS3 等进行设置 |
PWD | 表示当前目录 |
RANDOM | 生成一个 0~99999 的随机数 |
SECONDS | 自 shell 启动后的秒数 |
SHLVL | 与当前 shell 会话相关联的 shell 级别数。当登录到 shell 时,值为 1,每执行一次 Bash 命令后该级别数将递增 (例如使用 su 命令或输入 bash) |
TMOUT | 可以为该变量设置一个数字,表示 shell 可以空闲的秒数。在秒数到达后,shell 将会退出 (注销用户) |
3.6.1 创建和使用别名
使用 alias
命令可以列出所有别名以及创建别名
alias p = 'pwd ; ls -CF'
运行 p
命令,将运行 pwd
命令后运行 ls -CF
以列的形式列出该目录的内容
如果想删除,可使用 unalias
命令
3.6.2 退出 shell
输入 exit
或者按 Ctrl+D
3.7 创建自己的 shell 环境
可以通过调整 shell 以帮助更有效地工作
3.7.1 配置 shell
shell 的行为方式由多个配置文件所支持
文件 | 描述 |
---|---|
/etc/profile | 为每个用户设置了用户环境信息,当首次登录时执行该文件。该文件还从 /etc/profile.d 目录的配置文件中收集相关的 shell 设置。除了为诸如用户邮箱位置以及历史文件大小的信息设置环境变量,还提供了路径值 |
/etc/bashrc | 每次打开一个 Bash shell 时都会执行该文件,可通过每个用户的 ~/.bashrc 文件中的信息重写该文件。设置了默认的提示符,同时还可添加一个或多个别名 |
~/.bash_profile | 用来被每个用户用来输入 shell 具体用法的信息,只有当用户登录才会执行该文件。默认情况下,它设置一些环境变量并执行用户的 .bashrc 文件。该文件是添加环境变量的绝佳位置 |
~/.bashrc | 包含了特定于 Bash shell 的信息,当进行登录以及每次打开一个新 Bash shell 都会读取该文件。该文件是添加别名的好地方 |
~/.bash_logout | 每次注销时执行该文件,默认会清除屏幕 |
如果想更改 /etc/profile 或 /etc/bashrc 文件,则必须是 root 用户。一般创建 /etc/profile.d/custom.sh 文件来添加系统范围的设置,而不是直接编辑这些文件
- nano 编辑器
较为简单的文本编辑器,Ctrl+O
保存文件,Ctrl+X
退出文件
3.7.2 设置提示符
提示符由一组字符组成,每当 shell 准备接收命令时都会显示这组字符。PS1 环境变量设置了提示符所包含的内容,如果需要额外的输入u,可以使用 PS2、PS3 以及 PS4 的值
特殊字符 | 描述 |
---|---|
\! | 显示当前命令历史记录编号,包括为用户名存储的所有以前的命令 |
\# | 显示当前命令的命令编号,仅包括用于获取 shell 的命令 |
\$ | 根据用户类型的不同,显示用户提示符 $ 或 root 提示符 # |
\W | 仅显示当前工作的基名 |
\[ | 出现在非打印字符序列之前。可用来向提示符添加终端控制序列,比如改变颜色、添加闪烁效果或使字符变粗 (所使用的终端决定了最终可用的序列) |
\] | 紧跟在非打印字符序列之后 |
\\ | 显示一个反斜杠 |
\d | 显示当前日期的星期数、月份以及日子 |
\h | 显示正在运行 shell 的计算机的主机名 |
\n | 换行符 |
\nnn | 显示替换 nnn 的八进制数所表示的字符 |
\s | 显示当前 shell 的名称 |
\t | 以小时、分钟、秒的格式打印当前时间 |
\u | 打印当前用户名 |
\w | 显示当前工作目录的完整路径 |
如果仅临时修改,例如 export PS1="[\t\w]\$"
如果永久修改,需要向 ~/.bashrc 添加 PS1 值
阅读更多:Bash Prompt HOWTO
3.7.3 添加环境变量
有时可能需要向 .bashrc 文件添加一些环境变量
- TMOUT — 设置在 Bash 自动退出之前 shell 可以处于非活跃状态多长时间
- PATH — 设置了对所使用命令进行搜索的目录。例如为了添加目录 /home/yexca/bin,可添加以下代码 PATH=$PATH: /home/yexca/bin ; export PATH 该示例首先将所有当前的路径目录 ($PATH) 读取到新 PATH 变量中,然后添加 ~/bin 目录,最后导出新的 PATH 变量
切勿将
.
添加到 PATH 变量,可能存在安全风险
- WHATEVER — 可以创建自己的环境变量,为工作提供快捷方式。为这些变量选择一个未被使用的任何名称,并赋予一个有用的值。例如 MYWORKDIR=/home/yexca/work ; export MYWORKDIR 可通过输入
cd $MYWORKDIR
使设置的目录成为当前目录
3.8 获取关于命令的信息
一些命令内置于 shell 中,例如 help | less
以浏览帮助信息,或者 help command
以查看某命令的帮助信息
在命令中使用 --help
选项或 -h
选项以查看命令提供的帮助信息
还有 info
和 man command
命令学习某一特定命令
手册页是获取命令以及 Linux 系统中其他基本组件相关信息的最常用方法
手册页有 8 个章节
节数 | 节名称 | 描述 |
---|---|---|
1 | 用户命令 | 可以由普通用户通过 shell 运行的命令 |
2 | 系统调用 | 某一应用程序中用来调用系统内核的编程函数 |
3 | C 库函数 | 为特定编程库提供接口的编程函数 |
4 | 设备和特殊文件 | 表示硬件设备或软件设备的文件系统节点 |
5 | 文件格式和约定 | 文件类型或特定的配置文件 |
6 | 游戏 | 系统中可玩的游戏 |
7 | 杂项 | 对相关主题的 (如协议、文件系统) 概述 |
8 | 系统管理工具和守护进程 | 需要 root 或其他管理特权的命令 |
通过 man -k
可搜索手册页数据库。若无搜索结果可能是未初始化,使用 root 身份运行 mandb
以初始化数据库
通过例如 man 5 passwd
以显示第 5 节内容
浏览时通过 Page Down 和 Page UP 以翻页,或使用 Enter 与箭头键以移动一行。如果想要搜索,使用正斜杠 /
然后输入要搜索的内容,通过 n
重复向前搜索,N
以重复向后搜索。输入 q
以退出