Linux 手册
系统简介
学习路线
重要快捷键
Tab
: 可以进行命令补全,补全目录,补全命令参数
ctrl+c
: 强行终止当前程序
ctrl+d
: 键盘输入结束或者退出终端
ctrl+s
: 暂停当前程序,暂停后按下任意键恢复运行
ctrl+z
: 将当前程序放在后台运行,恢复到前台命令fg
ctrl+a
: 将光标移至输入行头,相当于Home
键
ctrl+e
: 将光标移至输入行末,相当于End
键
ctrl+k
: 删除光标所在位置到行末
alt+backspace
: 向前删除一个单词
shift+pageup
: 将终端显示向上滚动
shift+pagedown
: 将终端显示向下滚动
方向上键
: 恢复之前输入过的命令
Shell 常用通配符
字符 | 含义 |
---|---|
* |
匹配 0 或多个字符 |
? |
匹配任意一个字符 |
[list] |
匹配 list 中的任意单一字符 |
[^list] |
匹配 除 list 中的任意单一字符以外的字符 |
[c1-c2] |
匹配 c1-c2 中的任意单一字符 如:[0-9][a-z] |
{string1,string2,...} |
匹配 string1 或 string2 (或更多)其一字符串 |
{c1..c2} |
匹配 c1-c2 中全部字符 如{1…10} |
基础命令
获取命令帮助
1 |
|
获得更详细的帮助,你还可以使用info
命令,不过通常使用man
就足够了。如果你知道某个命令的作用,只是想快速查看一些它的某个具体参数的作用,那么你可以使用--help
参数
1 |
|
切换目录
1 |
|
查看当前目录
1 |
|
查看文件
1 |
|
用户系统操作
新建用户
1 |
|
useradd
只创建用户,不会创建用户密码和工作目录,创建完了需要使用 passwd <username>
去设置新用户的密码。adduser
在创建用户的同时,会创建工作目录和密码(提示你设置),做这一系列的操作。其实 useradd
、userdel
这类操作更像是一种命令,执行完了就返回。而 adduser
更像是一种程序,需要你输入、确定等一系列操作。
切换用户
1 |
|
退出当前用户
1 |
|
也可以使用快捷键Ctrl+D
查看用户组
1 |
|
在回显中冒号之前表示用户,后面表示该用户所属的用户组。
将其他用户加入 sudo 用户组
1 |
|
删除用户
1 |
|
使用 --remove-home
参数在删除用户时候会一并将该用户的工作目录一并删除。如果不使用那么系统会自动在 /home 目录为该用户保留工作目录。
文件系统操作
文件创建
1 |
|
目录创建
1 |
|
使用 -p
参数,同时创建父目录(如果不存在该父目录),如下我们同时创建一个多级目录(这在安装软件、配置安装路径时非常有用):
1 |
|
文件复制
1 |
|
如果需要复制一个目录则需要加上一个 -r
或者 -R
参数,表示递归复制
文件删除
文件删除
1 |
|
可以加入-f
参数来强行删除文件
1 |
|
删除目录
跟复制目录一样,要删除一个目录,也需要加上 -r
或 -R
参数:
1 |
|
遇到权限不足删除不了的目录也可以和删除文件一样加上 -f
参数:
1 |
|
移动文件
1 |
|
文件重命名
1 |
|
如果是要批量重命名可以使用rename
,需要自行安装
1 |
|
查看文件
cat 命令的使用
1 |
|
可以加上-n
参数显示行数
1 |
|
nl 命令的使用
相关参数
1 |
|
使用
例:
1 |
|
more 和 less 命令的使用
1 |
|
打开后默认只显示一屏内容,终端底部显示当前阅读的进度。可以使用 Enter
键向下滚动一行,使用 Space
键向下滚动一屏,按下 h
显示帮助,q
退出。
head 和 tail 命令的使用
一个是只查看文件的头几行(默认为 10 行,不足 10 行则显示全部)[head]
和尾几行[tail]
。
1 |
|
也可以加入-n
参数来查看指定行数
1 |
|
关于 tail
命令,不得不提的还有它一个很牛的参数 -f
,这个参数可以实现不停地读取某个文件的内容并显示。这可以让我们动态查看日志,达到实时监视的目的。可以自行去了解。
查看所有文件(包括隐藏文件)
1 |
|
查看某一个目录的完整属性,而不是显示目录里面的文件属性:
1 |
|
显示所有文件大小,并以普通人类能看懂的方式呈现:
1 |
|
其中小 s 为显示文件大小,大 S 为按文件大小排序
查看文件类型
1 |
|
与 Windows 不同的是,如果你新建了一个 shiyanlou.txt 文件,Windows 会自动把它识别为文本文件,而 file
命令会识别为一个空文件。在 Linux 中文件的类型不是根据文件后缀来判断的。当你在文件里输入内容后才会显示文件类型。
以较长格式列出文件
1 |
|
文件权限
- 文件类型
关于文件类型,这里有一点你必需时刻牢记 Linux 里面一切皆文件,正因为这一点才有了设备文件( /dev
目录下有各种设备文件,大都跟具体的硬件设备相关)这一说。 socket
:网络套接字,具体是什么,感兴趣的用户可以去学习实验楼的后续相关课程。pipe
管道,这个东西很重要,我们以后将会讨论到,这里你先知道有它的存在即可。软链接文件
:链接文件是分为两种的,另一种当然是“硬链接”(硬链接不常用,具体内容不作为本课程讨论重点,而软链接等同于 Windows 上的快捷方式,你记住这一点就够了)。
- 文件权限
读权限,表示你可以使用 cat <file name>
之类的命令来读取某个文件的内容;写权限,表示你可以编辑和修改某个文件的内容;
执行权限,通常指可以运行的二进制程序文件或者脚本文件,如同 Windows 上的 exe
后缀的文件,不过 Linux 上不是通过文件后缀名来区分文件的类型。你需要注意的一点是,一个目录同时具有读权限和执行权限才可以打开并查看内部文件,而一个目录要有写权限才允许在其中创建其它文件,这是因为目录文件实际保存着该目录里面的文件的列表等信息。
所有者权限,这一点相信你应该明白了,至于所属用户组权限,是指你所在的用户组中的所有其它用户对于该文件的权限,比如,你有一个 iPad,那么这个用户组权限就决定了你的兄弟姐妹有没有权限使用它破坏它和占有它。
- 链接数
链接到该文件所在的 inode 结点的文件名数目(关于这个概念涉及到 Linux 文件系统的相关概念知识,不在本课程的讨论范围,感兴趣的用户可以查看 硬链接和软链接的联系与区别)。
- 文件大小
以 inode 结点大小为单位来表示的文件大小,你可以给 ls 加上
-lh
参数来更直观的查看文件的大小。
明白了文件权限的一些概念,我们顺带补充一下关于 ls
命令的一些其它常用的用法:
- 显示除了
.
(当前目录)和..
(上一级目录)之外的所有文件,包括隐藏文件(Linux 下以.
开头的文件为隐藏文件)。
修改文件权限
更改方式
方式一:二进制数字
每个文件有三组固定的权限,分别对应拥有者,所属用户组,其他用户,记住这个顺序是固定的。文件的读写执行对应字母 rwx
,以二进制表示就是 111
,用十进制表示就是 7
,对进制转换不熟悉的同学可以看看 进制转换。例如我们刚刚新建的文件 test 的权限是 rw-rw-rw-
,换成对应的十进制表示就是 666,这就表示这个文件的拥有者,所属用户组和其他用户具有读写权限,不具有执行权限。
1 |
|
方式二:加减赋值操作
1 |
|
g
、o
还有 u
分别表示 group(用户组)、others(其他用户) 和 user(用户),+
和 -
分别表示增加和去掉相应的权限。
变更文件所有权
1 |
|
文件打包 (ZIP)
文件压缩
1 |
|
-r
参数表示递归打包包含子目录的全部内容,-q
参数表示为安静模式,即不向屏幕输出信息,-o
表示输出文件,需在其后紧跟打包输出文件名,-e
表示创建加密压缩包。
其中也可以设置压缩级别,添加一个参数用于设置压缩级别 -[1-9]
即可,其中1 表示最快压缩但体积大,9 表示体积最小但耗时最久。也可以增加 -x
,用于排除某些文件,如排除该目录下的zip
文件-x ~/*.zip
注意:这里只能使用绝对路径,否则不起作用。
与此同时我们也可以使用du
指令来查看默认压缩级别、最低、最高压缩级别及未压缩的文件的大小
1 |
|
其中-h
指human-readable
,便于阅读。而-d
指所查看文件的深度
注意: 关于 zip
命令,因为 Windows 系统与 Linux/Unix 在文本文件格式上的一些兼容问题,比如换行符(为不可见字符),在 Windows 为 CR+LF(Carriage-Return+Line-Feed:回车加换行),而在 Linux/Unix 上为 LF(换行),所以如果在不加处理的情况下,在 Linux 上编辑的文本,在 Windows 系统上打开可能看起来是没有换行的。如果想让在 Linux 创建的 zip 压缩文件在 Windows 上解压后没有任何问题,那么还需要对命令做一些修改:
1 |
|
需要加上 -l
参数将 LF
转换为 CR+LF
来达到以上目的。
文件解压
解压文件到当前目录
1 |
|
使用安静模式则可以加上指令-q
,如果需要解压到指定位置则在命令末尾加上-d [解压到的地址]
1 |
|
如果解压到的目录不存在的时候将会自动创建。如果只想查看压缩包内容则可以使用-l
命令
1 |
|
注意: 使用 unzip 解压文件时我们同样应该注意兼容问题,不过这里我们关心的不再是上面的问题,而是中文编码的问题,通常 Windows 系统上面创建的压缩文件,如果有有包含中文的文档或以中文作为文件名的文件时默认会采用 GBK 或其它编码,而 Linux 上面默认使用的是 UTF-8 编码,如果不加任何处理,直接解压的话可能会出现中文乱码的问题(有时候它会自动帮你处理),为了解决这个问题,我们可以在解压时指定编码类型。
使用 -O
(英文字母,大写 o)参数指定编码类型:
1 |
|
文件打包 (TAR)
文件压缩
只能实现对文件或目录(单独压缩目录中的文件)的压缩,没有实现对文件的打包压缩
创建一个tar
包
1 |
|
-P
保留绝对路径符,-c
表示创建一个 tar 包文件,-f
用于指定创建的文件名,注意文件名必须紧跟在 -f
参数之后,比如不能写成 tar -fc xxx.tar
,可以写成 tar -f xxx.tar -c ~
。还可以加上 -v
参数以可视的的方式输出打包的文件。
文件解压
解包一个文件(-x
参数)到指定路径的已存在目录(-C
参数):
1 |
|
如果仅查看压缩包内容则使用-t
参数
1 |
|
保留文件属性和跟随链接(符号链接或软链接),有时候我们使用 tar 备份文件当你在其他主机还原时希望保留文件的属性(-p
参数)和备份链接指向的源文件而不是链接本身(-h
参数):
1 |
|
如果需要创建/解压其他格式的压缩包只需要在对应位置上加上对应的参数即可
压缩文件格式 | 参数 |
---|---|
*.tar.gz |
-z |
*.tar.xz |
-J |
*tar.bz2 |
-j |
文件搜索
whereis
简单快速
1 |
|
whereis
只能搜索二进制文件(-b
),man 帮助文件(-m
)和源代码文件(-s
)。如果想要获得更全面的搜索结果可以使用 locate
命令。
locate
快而全
使用 locate
命令查找文件也不会遍历硬盘,它通过查询 /var/lib/mlocate/mlocate.db
数据库来检索信息。不过这个数据库也不是实时更新的,系统会使用定时任务每天自动执行 updatedb
命令来更新数据库。所以有时候你刚添加的文件,它可能会找不到,需要手动执行一次 updatedb
命令(在我们的环境中必须先执行一次该命令)。注意这个命令也不是内置的命令,在部分环境中需要手动安装,然后执行更新。
1 |
|
它可以用来查找指定目录下的不同文件类型,如查找 /etc
下所有以 sh 开头的文件:
1 |
|
注意,它不只是在 /etc 目录下查找,还会自动递归子目录进行查找。
如果想只统计数目可以加上 -c
参数,-i
参数可以忽略大小写进行查找,whereis
的 -b
、-m
、-s
同样可以使用。
which
小而精
which
本身是 Shell 内建的一个命令,我们通常使用 which
来确定是否安装了某个指定的程序,因为它只从 PATH
环境变量指定的路径中去搜索命令并且返回第一个搜索到的结果。也就是说,我们可以看到某个系统命令是否存在以及执行的到底是哪一个地方的命令。
1 |
|
find
精而细
find
应该是这几个命令中最强大的了,它不但可以通过文件类型、文件名进行查找而且可以根据文件的属性(如文件的时间戳,文件的权限等)进行搜索。
1 |
|
注意 find 命令的路径是作为第一个参数的, 基本命令格式为 find [path][option] [action] 。
与时间相关的命令参数:
参数 | 说明 |
---|---|
-atime |
最后访问时间 |
-ctime |
最后修改文件内容的时间 |
-mtime |
最后修改文件属性的时间 |
下面以 -mtime
参数举例:
-mtime n
:n 为数字,表示为在 n 天之前的“一天之内”修改过的文件-mtime +n
:列出在 n 天之前(不包含 n 天本身)被修改过的文件-mtime -n
:列出在 n 天之内(包含 n 天本身)被修改过的文件-newer file
:file 为一个已存在的文件,列出比 file 还要新的文件名
列出 home 目录中,当天(24 小时之内)有改动的文件:
1 |
|
列出用户家目录下比 /etc 目录新的文件:
1 |
|
磁盘管理
查看磁盘容量
1 |
|
物理主机上的 /dev/sda2
是对应着主机硬盘的分区,后面的数字表示分区号,数字前面的字母 a 表示第几块硬盘(也可能是可移动磁盘),你如果主机上有多块硬盘则可能还会出现 /dev/sdb
,/dev/sdc
这些磁盘设备都会在 /dev
目录下以文件的存在形式。
接着你还会看到"1k-块"这个陌生的东西,它表示以磁盘块大小的方式显示容量,后面为相应的以块大小表示的已用和可用容量,可以通过加上-h
参数更易于阅读。
1 |
|
查看目录容量
1 |
|
-d
参数指定查看目录的深度
1 |
|
常用参数
1 |
|
虚拟磁盘创建
dd 命令基本使用
dd
命令用于转换和复制文件,不过它的复制不同于 cp
。之前提到过关于 Linux 的很重要的一点,一切即文件,在 Linux 上,硬件的设备驱动(如硬盘)和特殊设备文件(如 /dev/zero
和 /dev/random
)都像普通文件一样,只是在各自的驱动程序中实现了对应的功能,dd
也可以读取文件或写入这些文件。这样,dd
也可以用在备份硬件的引导扇区、获取一定数量的随机数据或者空数据等任务中。dd
程序也可以在复制时处理数据,例如转换字节序、或在 ASCII 与 EBCDIC 编码间互换。
dd
的命令行语句与其他的 Linux 程序不同,因为它的命令行选项格式为 选项=值,而不是更标准的 –选项 值 或 -选项=值。dd
默认从标准输入中读取,并写入到标准输出中,但可以用选项 if
(input file,输入文件)和 of
(output file,输出文件)改变。
我们先来试试用 dd
命令从标准输入读入用户的输入到标准输出或者一个文件中:
1 |
|
上述命令从标准输入设备读入用户输入(缺省值,所以可省略)然后输出到 test 文件,bs
(block size)用于指定块大小(缺省单位为 Byte,也可为其指定如 K
,M
,G
等单位),count
用于指定块数量。如上图所示,我指定只读取总共 10 个字节的数据,当我输入了 hello shiyanlou
之后加上空格回车总共 16 个字节(一个英文字符占一个字节)内容,显然超过了设定大小。使用 du
和 cat
10 个字节(那个黑底百分号表示这里没有换行符),而其他的多余输入将被截取并保留在标准输入。
前面说到 dd
在拷贝的同时还可以实现数据转换,那下面就举一个简单的例子:将输出的英文字符转换为大写再写入文件:
1 |
|
使用 dd 命令创建虚拟镜像文件
通过上面一小节,你应该掌握了 dd
的基本使用,下面就来使用 dd
命令来完成创建虚拟磁盘的第一步。
从 /dev/zero
设备创建一个容量为 256M 的空文件:
1 |
|
然后我们要将这个文件格式化(写入文件系统),这里我们要学到一个(准确的说是一组)新的命令来完成这个需求。
使用 mkfs 命令格式化磁盘(我们这里是自己创建的虚拟磁盘镜像)
你可以在命令行输入 sudo mkfs
然后按下 <Tab>
键,你可以看到很多个以 mkfs 为前缀的命令,这些不同的后缀其实就是表示着不同的文件系统,可以用 mkfs 格式化成的文件系统。
我们可以简单的使用下面的命令来将我们的虚拟磁盘镜像格式化为 ext4
文件系统:
1 |
|
可以看到实际 mkfs.ext4
是使用 mke2fs
来完成格式化工作的。mke2fs
的参数很多,不过我们也不会经常格式化磁盘来玩,所以就掌握这基本用法吧,等你有特殊需求时,再查看 man 文档解决。
更多关于文件系统的知识,请查看 wiki: 文件系统 ext3,ext4
如果你想知道 Linux 支持哪些文件系统你可以输入 ls -l /lib/modules/$(uname -r)/kernel/fs
查看。
使用 mount 命令挂载磁盘到目录树
用户在 Linux/UNIX 的机器上打开一个文件以前,包含该文件的文件系统必须先进行挂载的动作,此时用户要对该文件系统执行 mount
的指令以进行挂载。该指令通常是使用在 USB 或其他可移除存储设备上,而根目录则需要始终保持挂载的状态。又因为 Linux/UNIX 文件系统可以对应一个文件而不一定要是硬件设备,所以可以挂载一个包含文件系统的文件到目录树。
Linux/UNIX 命令行的 mount
指令是告诉操作系统,对应的文件系统已经准备好,可以使用了,而该文件系统会对应到一个特定的点(称为挂载点)。挂载好的文件、目录、设备以及特殊文件即可提供用户使用。
我们先来使用 mount
来查看下主机已经挂载的文件系统:
1 |
|
输出的结果中每一行表示一个设备或虚拟设备,每一行最前面是设备名,然后是 on 后面是挂载点,type 后面表示文件系统类型,再后面是挂载选项(比如可以在挂载时设定以只读方式挂载等等)。
那么我们如何挂载真正的磁盘到目录树呢,mount
命令的一般格式如下:
1 |
|
一些常用操作:
1 |
|
现在直接来挂载我们创建的虚拟磁盘镜像到 /mnt
目录:
1 |
|
使用 umount 命令卸载已挂载磁盘
1 |
|
使用 fdisk 为磁盘分区
(关于分区的一些概念不清楚的用户请参看 主引导记录)
1 |
|
输出结果中开头显示了我主机上的磁盘的一些信息,包括容量扇区数,扇区大小,I/O 大小等信息。
我们重点看一下中间的分区信息,/dev/sda1
,/dev/sda2
为主分区分别安装了 Windows 和 Linux 操作系统,/dev/sda3
为交换分区(可以理解为虚拟内存),/dev/sda4
为扩展分区其中包含 /dev/sda5
,/dev/sda6
,/dev/sda7
,/dev/sda8
四个逻辑分区,因为主机上有几个分区之间有空隙,没有对齐边界扇区,所以分区之间不是完全连续的。
1 |
|
在进行操作前我们首先应先规划好我们的分区方案,这里我将在使用 128M(可用 127M 左右)的虚拟磁盘镜像创建一个 30M 的主分区剩余部分为扩展分区包含 2 个大约 45M 的逻辑分区。
操作完成后输入 p
查看结果如下:
最后不要忘记输入 w
写入分区表。
使用 losetup 命令建立镜像与回环设备的关联
1 |
|
然后再使用 mkfs
格式化各分区(前面我们是格式化整个虚拟磁盘镜像文件或磁盘),不过格式化之前,我们还要为各分区建立虚拟设备的映射,用到 kpartx
工具,需要先安装:
1 |
|
接着再是格式化,我们将其全部格式化为 ext4:
1 |
|
格式化完成后在 /media
目录下新建四个空目录用于挂载虚拟磁盘:
1 |
|
然后:
1 |
|
Linux 下帮助命令
内建命令与外部命令
什么是内建命令,什么是外部命令呢?这和帮助命令又有什么关系呢?
因为有一些查看帮助的工具在内建命令与外建命令上是有区别对待的。
内建命令实际上是 shell 程序的一部分,其中包含的是一些比较简单的 Linux 系统命令,这些命令是写在 bash 源码的 builtins 里面的,由 shell 程序识别并在 shell 程序内部完成运行,通常在 Linux 系统加载运行时 shell 就被加载并驻留在系统内存中。而且解析内部命令 shell 不需要创建子进程,因此其执行速度比外部命令快。比如:history、cd、exit 等等。
外部命令是 Linux 系统中的实用程序部分,因为实用程序的功能通常都比较强大,所以其包含的程序量也会很大,在系统加载时并不随系统一起被加载到内存中,而是在需要时才将其调入内存。虽然其不包含在 shell 中,但是其命令执行过程是由 shell 程序控制的。外部命令是在 Bash 之外额外安装的,通常放在/bin,/usr/bin,/sbin,/usr/sbin 等等。比如:ls、vi 等。
简单来说就是:一个是天生自带的天赋技能,一个是后天得来的附加技能。我们可以使用 type 命令来区分命令是内建的还是外部的。例如这两个得出的结果是不同的
1 |
|
得到的是两种结果,若是对 ls 你还能得到第三种结果
1 |
|
help 命令
help
命令是用于显示 shell
内建命令的简要帮助信息。帮助信息中显示有该命令的简要说明以及一些参数的使用以及说明,一定记住 help
命令只能用于显示内建命令的帮助信息,如果是外部命令则可以在命令后加上--help
参数。
man 命令
man
得到的内容比用 help
更多更详细,而且 man
没有内建与外部命令的区分,因为 man 工具是显示系统手册页中的内容,也就是一本电子版的字典,这些内容大多数都是对命令的解释信息,还有一些相关的描述。通过查看系统文档中的 man
也可以得到程序的更多相关信息和 Linux
的更多特性。
在尝试上面这个命令时我们会发现最左上角显示“ LS (1)”,在这里,“ LS ”表示手册名称,而“(1)”表示该手册位于第一章节。这个章节又是什么?在 man 手册中一共有这么几个章节
章节数 | 说明 |
---|---|
1 |
Standard commands (标准命令) |
2 |
System calls (系统调用) |
3 |
Library functions (库函数) |
4 |
Special devices (设备说明) |
5 |
File formats (文件格式) |
6 |
Games and toys (游戏和娱乐) |
7 |
Miscellaneous (杂项) |
8 |
Administrative Commands (管理员命令) |
9 |
其他(Linux 特定的), 用来存放内核例行程序的文档。 |
打开手册之后我们可以通过 pgup 与 pgdn 或者上下键来上下翻看,可以按 q 退出当前页面
info 命令
使用info
命令需要手动安装
1 |
|
得到的信息比 man 还要多,与此同时,man 和 info 就像两个集合,它们有一个交集部分,但与 man 相比,info 工具可显示更完整的 GNU 工具信息。若 man 页包含的某个工具的概要信息在 info 中也有介绍,那么 man 页中会有“请参考 info 页更详细内容”的字样。
Linux 任务计划 crontab
crontab 简介
crontab 命令从输入设备读取指令,并将其存放于 crontab 文件中,以供之后读取和执行。通常,crontab 储存的指令被守护进程激活,crond 为其守护进程,crond 常常在后台运行,每一分钟会检查一次是否有预定的作业需要执行。
通过 crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell 脚本。时间间隔的单位可以是分钟、小时、日、月、周的任意组合。
这里我们看一看 crontab 的格式:
1 |
|
我们通过下面一个命令来添加一个计划任务:
1 |
|
第一次启动会出现这样一个画面,这是让我们选择编辑的工具,选择第二个基本的 vim 就可以了。
而选择后我们会进入这样一个画面,这就是添加计划的地方了,与一般的配置文档相同,以#号开头的都是注释,通过文档的最后一排我们可以猜猜 crontab 的格式是什么样的呢?
1 |
|
在了解命令格式之后,我们通过这样的一个例子来完成一个任务的添加,在文档的最后一排加上这样一排命令,该任务是每分钟我们会在/home/shiyanlou 目录下创建一个以当前的年月日时分秒为名字的空白文件
1 |
|
注意:
“ % ” 在 crontab 文件中,有结束命令行、换行、重定向的作用,前面加 ” \ ” 符号转义,否则,“ % ” 符号将执行其结束命令行或者换行的作用,并且其后的内容会被做为标准输入发送给前面的命令。
添加成功后我们会得到最后一排 installing new crontab 的一个提示:
当然我们也可以通过这样的一个指令来查看我们添加了哪些任务:
1 |
|
通过图中的显示,我们也可以看出,我们正确的保存并且添加成功了该任务的:
虽然我们添加了任务,但是如果 cron
的守护进程并没有启动,它根本都不会监测到有任务,当然也就不会帮我们执行,我们可以通过以下 2 种方式来确定我们的 cron
是否成功的在后台启动,默默的帮我们做事,若是没有就得执行上文准备中的第二步了。
1 |
|
通过下图可以看到任务在创建之后,执行了几次,生成了一些文件,且每分钟生成一个:
我们通过这样一个命令可以查看到执行任务命令之后在日志中的信息反馈:
1 |
|
从图中我们可以看到分别在 13 点 28、29、30 分的 01 秒为我们在 shiyanlou 用户的家目录下创建了文件。
当我们并不需要这个任务的时候我们可以使用这么一个命令去删除任务:
1 |
|
通过图中我们可以看出我们删除之后再查看任务列表,系统已经显示该用户并没有任务哦。
crontab 的深入
每个用户使用 crontab -e
添加计划任务,都会在 /var/spool/cron/crontabs
中添加一个该用户自己的任务文档,这样目的是为了隔离。
如果是系统级别的定时任务,需要 root 权限执行的任务应该怎么处理?
只需要使用 sudo
编辑 /etc/crontab
文件就可以。
cron
服务监测时间最小单位是分钟,所以 cron
会每分钟去读取一次 /etc/crontab
与 /var/spool/cron/crontabs
里面的內容。
在 /etc
目录下,cron
相关的目录有下面几个:
每个目录的作用:
/etc/cron.daily
,目录下的脚本会每天执行一次,在每天的 6 点 25 分时运行;/etc/cron.hourly
,目录下的脚本会每个小时执行一次,在每小时的 17 分钟时运行;/etc/cron.monthly
,目录下的脚本会每月执行一次,在每月 1 号的 6 点 52 分时运行;/etc/cron.weekly
,目录下的脚本会每周执行一次,在每周第七天的 6 点 47 分时运行;
系统默认执行时间可以根据需求进行修改。
命令执行顺序控制与管道
命令执行顺序
在终端中简单的顺序执行你可以使用 ;
来完成,比如你可以:
1 |
|
如果我们在让它自动顺序执行命令时,前面的命令执行不成功,而后面的命令又依赖于上一条命令的结果,那么就会造成花了时间,最终却得到一个错误的结果,而且有时候直观的看你还无法判断结果是否正确。那么我们需要能够有选择性的来执行命令,比如上一条命令执行成功才继续下一条,或者不成功又该做出其它什么处理,比如我们使用 which
来查找是否安装某个命令,如果找到就执行该命令,否则什么也不做,虽然这个操作没有什么实际意义,但可帮你更好的理解一些概念:
1 |
|
你如果没有安装 cowsay
,你可以先执行一次上述命令,你会发现什么也没发生,你再安装好之后你再执行一次上述命令,你也会发现一些惊喜。
上面的 &&
就是用来实现选择性执行的,它表示如果前面的命令执行结果(不是表示终端输出的内容,而是表示命令执行状态的结果)返回 0 则执行后面的,否则不执行,你可以从 $?
环境变量获取上一次命令的返回结果。
学习过 C 语言的应该知道在 C 语言里面 &&
表示逻辑与,而且还有一个 ||
表示逻辑或,同样 Shell 也有一个 ||
,它们的区别就在于,shell 中的这两个符号除了也可用于表示逻辑与和或之外,就是可以实现这里的命令执行顺序的简单控制。||
在这里就是与 &&
相反的控制效果,当上一条命令执行结果为 ≠0(\$?≠0)
时则执行它后面的命令:
1 |
|
除了上述基本的使用之外,我们还可以结合着 &&
和 ||
来实现一些操作,比如:
1 |
|
用流程图可以理解为:
管道
比如查看 /etc
目录下有哪些文件和目录,使用 ls
命令来查看:
1 |
|
有太多内容,屏幕不能完全显示,这时候可以使用滚动条或快捷键滚动窗口来查看。不过这时候可以使用管道:
1 |
|
通过管道将前一个命令(ls
)的输出作为下一个命令(less
)的输入,然后就可以一行一行地看。
cut 命令
打印 /etc/passwd
文件中以 :
为分隔符的第 1 个字段和第 6 个字段分别表示用户名和其家目录:
1 |
|
打印 /etc/passwd
文件中每一行的前 N 个字符:
1 |
|
grep 命令
grep
命令是很强大的,也是相当常用的一个命令,它结合正则表达式可以实现很复杂却很高效的匹配和查找,不过在学习正则表达式之前,这里介绍它简单的使用,而关于正则表达式后面将会有单独一小节介绍到时会再继续学习 grep
命令和其他一些命令。
grep
命令的一般形式为:
1 |
|
还是先体验一下,我们搜索/home/shiyanlou
目录下所有包含"shiyanlou"的文本文件,并显示出现在文本中的行号:
1 |
|
-r
参数表示递归搜索子目录中的文件,-n
表示打印匹配项行号,-I
表示忽略二进制文件。这个操作实际没有多大意义,但可以感受到 grep
命令的强大与实用。
当然也可以在匹配字段中使用正则表达式,下面简单的演示:
1 |
|
其中$
表示一行的末尾
wc 命令
wc 命令用于统计并输出一个文件中行、单词和字节的数目,比如输出 /etc/passwd
文件的统计信息:
1 |
|
分别只输出行数、单词数、字节数、字符数和输入文本中最长一行的字节数:
1 |
|
注意:对于西文字符来说,一个字符就是一个字节,但对于中文字符一个汉字是大于 2 个字节的,具体数目是由字符编码决定的。
再来结合管道来操作一下,下面统计 /etc 下面所有目录数:
1 |
|
sort 命令
功能很简单就是将输入按照一定方式排序,然后再输出,它支持的排序有按字典排序,数字排序,按月份排序,随机排序,反转排序,指定特定字段进行排序等等。
默认为字典排序:
1 |
|
反转排序:
1 |
|
按特定字段排序:
1 |
|
上面的-t
参数用于指定字段的分隔符,这里是以":"作为分隔符;-k 字段号
用于指定对哪一个字段进行排序。这里/etc/passwd
文件的第三个字段为数字,默认情况下是以字典序排序的,如果要按照数字排序就要加上-n
参数:
1 |
|
注意观察第二个冒号后的数字:
uniq 命令
uniq
命令可以用于过滤或者输出重复行。
- 过滤重复行
我们可以使用 history
命令查看最近执行过的命令(实际为读取 ${SHELL}_history
文件,如环境中的 .zsh_history
文件),不过你可能只想查看使用了哪个命令而不需要知道具体干了什么,那么你可能就会要想去掉命令后面的参数然后去掉重复的命令:
1 |
|
然后经过层层过滤,你会发现确是只输出了执行的命令那一列,不过去重效果好像不明显,仔细看你会发现它确实去重了,只是不那么明显,之所以不明显是因为 uniq
命令只能去连续重复的行,不是全文去重,所以要达到预期效果,我们先排序:
1 |
|
这就是 Linux/UNIX 哲学吸引人的地方,大繁至简,一个命令只干一件事却能干到最好。
- 输出重复行
1 |
|
文本处理命令还有很多,下一节将继续介绍一些常用的文本处理的命令。
文本处理
tr 命令
tr 命令可以用来删除一段文本信息中的某些文字。或者将其进行转换。
使用方式
1 |
|
常用的选项有
选项 | 说明 |
---|---|
-d |
删除和 set1 匹配的字符,注意不是全词匹配也不是按字符顺序匹配 |
-s |
去除 set1 指定的在输入文本中连续并重复的字符 |
操作举例
1 |
|
与此同时tr
命令也可以用于替换,比如需要把$
替换为^M
,则可以写:
1 |
|
col 命令
col 命令可以将Tab
换成对等数量的空格键,或反转这个操作。
使用方式
1 |
|
常用的选项有
选项 | 说明 |
---|---|
-x |
将Tab 转换为空格 |
-h |
将空格转换为Tab (默认选项) |
操作举例
1 |
|
join 命令
学过数据库的用户对这个应该不会陌生,这个命令就是用于将两个文件中包含相同内容的那一行合并在一起。
使用方式
1 |
|
常用的选项有
选项 | 说明 |
---|---|
-t |
指定分隔符,默认为空格 |
-i |
忽略大小写的差异 |
-1 |
指明第一个文件要用哪个字段来对比,默认对比第一个字段 |
-2 |
指明第二个文件要用哪个字段来对比,默认对比第一个字段 |
操作举例
1 |
|
paste 命令
paste
这个命令与join
命令类似,它是在不对比数据的情况下,简单地将多个文件合并一起,以Tab
隔开。
使用方式
1 |
|
常用的选项有
选项 | 说明 |
---|---|
-d |
指定合并的分隔符,默认为 Tab |
-s |
不合并到一行,每个文件为一行 |
操作举例
1 |
|
数据流重定向
简单重定向
在更多了解 Linux 的重定向之前,我们需要先知道一些基本的东西,前面我们已经提到过 Linux 默认提供了三个特殊设备,用于终端的显示和输出,分别为 stdin
(标准输入,对应于你在终端的输入),stdout
(标准输出,对应于终端的输出),stderr
(标准错误输出,对应于终端的输出)。
文件描述符 | 设备文件 | 说明 |
---|---|---|
0 |
/dev/stdin |
标准输入 |
1 |
/dev/stdout |
标准输出 |
2 |
/dev/stderr |
标准错误 |
文件描述符:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于 UNIX、Linux 这样的操作系统。
我们可以这样使用这些文件描述符。例如默认使用终端的标准输入作为命令的输入和标准输出作为命令的输出:
1 |
|
将 cat 的连续输出(heredoc 方式)重定向到一个文件:
1 |
|
将一个文件作为命令的输入,标准输出作为命令的输出:
1 |
|
将 echo 命令通过管道传过来的数据作为 cat 命令的输入,将标准输出作为命令的输出:
1 |
|
将 echo 命令的输出从默认的标准输出重定向到一个普通文件:
1 |
|
初学者这里要注意不要将管道和重定向混淆,管道默认是连接前一个命令的输出到下一个命令的输入,而重定向通常是需要一个文件来建立两个命令的连接,你可以仔细体会一下上述第三个操作和最后两个操作的异同点。
标准错误重定向
重定向标准输出到文件,这是一个很实用的操作,另一个很实用的操作是将标准错误重定向,标准输出和标准错误都被指向伪终端的屏幕显示,所以我们经常看到的一个命令的输出通常是同时包含了标准输出和标准错误的结果的。比如下面的操作:
1 |
|
遗憾的是,这里依然出现了那条错误信息,这正是因为如我上面说的那样,标准输出和标准错误虽然都指向终端屏幕,实际它们并不一样。那有的时候我们就是要隐藏某些错误或者警告,那又该怎么做呢。这就需要用到我们前面讲的文件描述符了:
1 |
|
注意你应该在输出重定向文件描述符前加上&
,否则 shell 会当做重定向到一个文件名为 1 的文件中
使用 tee 命令同时重定向到多个文件
除了需要将输出重定向到文件,也需要将信息打印在终端。那么你可以使用 tee
命令来实现:
1 |
|
永久重定向
你应该可以看出我们前面的重定向操作都只是临时性的,即只对当前命令有效,那如何做到永久有效呢,比如在一个脚本中,你需要某一部分的命令的输出全部进行重定向,难道要让你在每个命令上面加上临时重定向的操作嘛?
当然不需要,我们可以使用 exec
命令实现永久重定向。exec
命令的作用是使用指定的命令替换当前的 Shell,即使用一个进程替换当前进程,或者指定新的重定向:
1 |
|
创建输出文件描述符
在 Shell 中有 9 个文件描述符。上面我们使用了也是它默认提供的 0,1,2 号文件描述符。另外我们还可以使用 3-8 的文件描述符,只是它们默认没有打开而已。你可以使用下面命令查看当前 Shell 进程中打开的文件描述符:
1 |
|
同样使用 exec
命令可以创建新的文件描述符:
1 |
|
关闭文件描述符
如上面我们打开的 3 号文件描述符,可以使用如下操作将它关闭:
1 |
|
完全屏蔽命令的输出
在 Linux 中有一个被称为黑洞的设备文件,所有导入它的数据都将被吞噬。
在类 UNIX 系统中,/dev/null,或称空设备,是一个特殊的设备文件,它通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个 EOF。
我们可以利用 /dev/null
屏蔽命令的输出:
1 |
|
上面这样的操作将使你得不到任何输出结果。
使用 xargs 分割参数列表
xargs 是一条 UNIX 和类 UNIX 操作系统的常用命令。它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。
这个命令在有些时候十分有用,特别是当用来处理产生大量输出结果的命令如 find
,locate
和 grep
的结果,详细用法请参看 man 文档。
1 |
|
上面这个命令用于将 /etc/passwd
文件按 :
分割取第一个字段排序后,使用 echo
命令生成一个列表。
正则表达式
基本语法
一个正则表达式通常被称为一个模式(pattern),为用来描述或者匹配一系列符合某个句法规则的字符串。
选择
|
竖直分隔符表示选择,例如 boy|girl
可以匹配 boy
或者 girl
。
数量限定
数量限定除了我们举例用的 *
还有 +
加号 ?
问号,如果在一个模式中不加数量限定符则表示出现一次且仅出现一次:
+
表示前面的字符必须出现至少一次(1 次或多次),例如goo+gle
可以匹配gooogle
,goooogle
等;?
表示前面的字符最多出现一次(0 次或 1 次),例如,colou?r
,可以匹配color
或者colour
;*
星号代表前面的字符可以不出现,也可以出现一次或者多次(0 次、或 1 次、或多次),例如,0*42
可以匹配 42、042、0042、00042 等。
范围和优先级
()
圆括号可以用来定义模式字符串的范围和优先级,这可以简单的理解为是否将括号内的模式串作为一个整体。例如,gr(a|e)y
等价于 gray|grey
,(这里体现了优先级,竖直分隔符用于选择 a
或者 e
而不是 gra
和 ey
),(grand)?father
匹配 father
和 grandfather
(这里体现了范围,?
将圆括号内容作为一个整体匹配)。
语法(部分)
正则表达式有多种不同的风格,下面列举一些常用的作为 PCRE 子集的适用于 perl
和 python
编程语言及 grep
或 egrep
的正则表达式匹配规则:
PCRE(Perl Compatible Regular Expressions 中文含义:perl 语言兼容正则表达式)是一个用 C 语言编写的正则表达式函数库,由菲利普.海泽(Philip Hazel)编写。PCRE 是一个轻量级的函数库,比 Boost 之类的正则表达式库小得多。PCRE 十分易用,同时功能也很强大,性能超过了 POSIX 正则表达式库和一些经典的正则表达式库。
(由于 markdown 表格解析的问题,下面的竖直分隔符 |
用全角字符代替,实际使用时请换回半角字符。
字符 | 描述 |
---|---|
\ |
将下一个字符标记为一个特殊字符、或一个原义字符。 例如 n 匹配字符 n 。\n 匹配一个换行符。序列 \\ 匹配 \ 而 \( 则匹配 ( 。 |
^ |
匹配输入字符串的开始位置。 |
$ |
匹配输入字符串的结束位置。 |
{n} |
n 是一个非负整数。匹配确定的 n 次。例如 o{2} 不能匹配 Bob 中的 o ,但是能匹配 food 中的两个 o 。 |
{n,} |
n 是一个非负整数。至少匹配 n 次。例如 o{2,} 不能匹配 Bob 中的 o ,但能匹配 foooood 中的所有 o 。o{1,} 等价于 o+ 。o{0,} 则等价于 o* 。 |
{n,m} |
m 和 n 均为非负整数,其中 n<=m 。最少匹配 n 次且最多匹配 m 次。例如,o{1,3} 将匹配 fooooood 中的前三个 o 。o{0,1} 等价于 o? 。请注意在逗号和两个数之间不能有空格。 |
* |
匹配前面的子表达式零次或多次。例如,zo* 能匹配 z 、zo 以及 zoo 。* 等价于 {0,} 。 |
+ |
匹配前面的子表达式一次或多次。例如,zo+ 能匹配 zo 以及 zoo ,但不能匹配 z 。+ 等价于 {1,} 。 |
? |
匹配前面的子表达式零次或一次。例如,do(es)? 可以匹配 do 或 does 中的 do 。? 等价于 {0,1} 。 |
? |
当该字符紧跟在任何一个其他限制符(* ,+ ,? ,{n} ,{n,} ,{n,m} )后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 oooo ,o+? 将匹配单个 o ,而 o+ 将匹配所有 o 。 |
. |
匹配除 \n 之外的任何单个字符。要匹配包括 \n 在内的任何字符,请使用类似 (.|\n) 的模式。 |
(pattern) |
匹配 pattern 并获取这一匹配的子字符串。该子字符串用于向后引用。要匹配圆括号字符,请使用 \( 和 \) 。 |
x | y | 匹配 x 或 y。例如,“z | food”能匹配 z 或 food 。“(z | f)ood”则匹配 zood 或 food 。 |
[xyz] |
字符集合(character class)。匹配所包含的任意一个字符。例如,[abc] 可以匹配 plain 中的 a 。其中特殊字符仅有反斜线 \ 保持特殊含义,用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符^如果出现在首位则表示负值字符集合;如果出现在字符串中间就仅作为普通字符。连字符 - 如果出现在字符串中间表示字符范围描述;如果出现在首位则仅作为普通字符。 |
[^xyz] |
排除型(negate)字符集合。**匹配未列出的任意字符。**例如,[^abc] 可以匹配 plain 中的 plin 。 |
[a-z] |
字符范围。**匹配指定范围内的任意字符。**例如,[a-z] 可以匹配 a 到 z 范围内的任意小写字母字符。 |
[^a-z] |
排除型的字符范围。匹配任何不在指定范围内的任意字符。例如,[^a-z] 可以匹配任何不在 a 到 z 范围内的任意字符。 |
优先级
优先级为从上到下从左到右,依次降低:
运算符 | 说明 |
---|---|
\ |
转义符 |
() ,(?:) ,(?=) ,[] |
括号和中括号 |
* ,+ ,? ,{n} ,{n,} ,{n,m} |
限定符 |
^ ,$ ,\ 任何元字符 |
定位点和序列 |
| | 选择 |
更多正则表达式的内容可以参考以下链接:
regex 的思导图:
基本操作
grep
命令用于打印输出文本中匹配的模式串,它使用正则表达式作为模式匹配的条件。grep
支持三种正则表达式引擎,分别用三个参数指定:
参数 | 说明 |
---|---|
-E |
POSIX 扩展正则表达式,ERE |
-G |
POSIX 基本正则表达式,BRE |
-P |
Perl 正则表达式,PCRE |
不过在你没学过 perl 语言的大多数情况下你将只会使用到 ERE
和 BRE
,所以我们接下来的内容都不会讨论到 PCRE 中特有的一些正则表达式语法(它们之间大部分内容是存在交集的,所以你不用担心会遗漏多少重要内容)。
在通过grep
命令使用正则表达式之前,先介绍一下它的常用参数:
参数 | 说明 |
---|---|
-b |
将二进制文件作为文本来进行匹配 |
-c |
统计以模式匹配的数目,可以用于统计文本中某个字符串出现的次数 |
-i |
忽略大小写 |
-n |
显示匹配文本所在行的行号 |
-v |
反选,输出不匹配行的内容 |
-r |
递归匹配查找 |
-A n |
n 为正整数,表示 after 的意思,除了列出匹配行之外,还列出后面的 n 行 |
-B n |
n 为正整数,表示 before 的意思,除了列出匹配行之外,还列出前面的 n 行 |
--color=auto |
将输出中的匹配项设置为自动颜色显示 |
注:在大多数发行版中是默认设置了 grep 的颜色的,你可以通过参数指定或修改
GREP_COLOR
环境变量。
基本正则表达式的使用 (BRE)
查找位置
1 |
|
查找数量
1 |
|
注意:其中 \n
为换行符
进行选择
1 |
|
下面包含完整的特殊符号及说明:
特殊符号 | 说明 |
---|---|
[:alnum:] |
代表英文大小写字母及数字,亦即 0-9,A-Z,a-z |
[:alpha:] |
代表任何英文大小写字母,亦即 A-Z,a-z |
[:blank:] |
代表空白键与 [Tab] 按键两者 |
[:cntrl:] |
代表键盘上面的控制按键,亦即包括 CR,LF,Tab,Del… |
[:digit:] |
代表数字而已,亦即 0-9 |
[:graph:] |
除了空白字节(空白键与 [Tab] 按键)外的其他所有按键 |
[:lower:] |
代表小写字母,亦即 a-z |
[:print:] |
代表任何可以被列印出来的字符 |
[:punct:] |
代表标点符号(punctuation symbol),即:" ,' ,? ,! ,; ,: ,# ,$ … |
[:upper:] |
代表大写字母,亦即 A-Z |
[:space:] |
任何会产生空白的字符,包括空格键,[Tab] ,CR 等等 |
[:xdigit:] |
代表 16 进位的数字类型,因此包括: 0-9,A-F,a-f 的数字与字节 |
注意:之所以要使用特殊符号,是因为上面的
[a-z]
不是在所有情况下都管用,这还与主机当前的语系有关,即设置在LANG
环境变量的值,zh_CN.UTF-8
的话[a-z]
,即为所有小写字母,其它语系可能是大小写交替的如,“a A b B…z Z”,[a-z]
中就可能包含大写字母。所以在使用[a-z]
时请确保当前语系的影响,使用[:lower:]
则不会有这个问题。
1 |
|
当
^
放到中括号内为排除字符,否则表示行首。
扩展正则表达式的使用 (ERE)
要通过 grep
使用扩展正则表达式需要加上 -E
参数,或使用 egrep
。
- 数量
1 |
|
推荐掌握
{n,m}
即可+
,?
,*
这几个不太直观,且容易弄混淆。
- 选择
1 |
|
因为
.
号有特殊含义,所以需要转义。
sed 编辑器
常用参数
sed 命令基本格式:
1 |
|
参数 | 说明 |
---|---|
-n |
安静模式,只打印受影响的行,默认打印输入数据的全部内容 |
-e |
用于在脚本中添加多个执行命令一次执行,在命令行中执行多个命令通常不需要加该参数 |
-f filename |
指定执行 filename 文件中的命令 |
-r |
使用扩展正则表达式,默认为标准正则表达式 |
-i |
将直接修改输入文件内容,而不是打印到标准输出设备 |
执行命令
sed 执行命令格式:
1 |
|
其中一些命令可以在后面加上作用范围,形如:
1 |
|
其中 n1,n2
表示输入内容的行号,它们之间为 ,
逗号则表示从 n1 到 n2 行,如果为 ~
波浪号则表示从 n1 开始以 step 为步进的所有行;command 为执行动作,下面为一些常用动作指令:
命令 | 说明 |
---|---|
s |
行内替换 |
c |
整行替换 |
a |
插入到指定行的后面 |
i |
插入到指定行的前面 |
p |
打印指定行,通常与 -n 参数配合使用 |
d |
删除指定行 |
操作举例
打印指定行
1 |
|
行内替换
1 |
|
行内替换可以结合正则表达式使用。
删除某行
1 |
|
更多 sed 的高级用法,你可以参看如下链接:
awk 文本处理语言
基础概念
awk 所有的操作都是基于 pattern(模式)—action(动作)对来完成的,如下面的形式:
1 |
|
你可以看到就如同很多编程语言一样,它将所有的动作操作用一对 {}
花括号包围起来。其中 pattern 通常是表示用于匹配输入的文本的“关系式”或“正则表达式”,action 则是表示匹配后将执行的动作。在一个完整 awk 操作中,这两者可以只有其中一个,如果没有 pattern 则默认匹配输入的全部文本,如果没有 action 则默认为打印匹配内容到屏幕。
awk
处理文本的方式,是将文本分割成一些“字段”,然后再对这些字段进行处理,默认情况下,awk 以空格作为一个字段的分割符,不过这不是固定的,你可以任意指定分隔符。
基本命令格式
1 |
|
其中 -F
参数用于预先指定前面提到的字段分隔符(还有其他指定字段的方式),-v
用于预先为 awk
程序指定变量,-f
参数用于指定 awk
命令要执行的程序文件,或者在不加 -f
参数的情况下直接将程序语句放在这里,最后为 awk
需要处理的文本输入,且可以同时输入多个文本文件。
文本输出
使用 awk 将文本内容打印到终端:
1 |
|
在这个操作中是省略了 pattern
,所以 awk
会默认匹配输入文本的全部内容,然后在 {}
花括号中执行动作,即 print
打印所有匹配项,这里是全部文本内容。
字段替换
- 将第一行的每个字段单独显示为一行:
1 |
|
说明:你首先应该注意的是,这里我使用了 awk
语言的分支选择语句if
,它的使用和很多高级语言如 C/C++
语言基本一致,如果你有这些语言的基础,这里将很好理解。另一个你需要注意的是 NR
与 OFS
,这两个是 awk
内建的变量,NR
表示当前读入的记录数,你可以简单的理解为当前处理的行数,OFS
表示输出时的字段分隔符,默认为" "空格,如上图所见,我们将字段分隔符设置为 \n
换行符,所以第一行原本以空格为字段分隔的内容就分别输出到单独一行了。然后是 $N
其中 N 为相应的字段号,这也是 awk
的内建变量,它表示引用相应的字段,因为我们这里第一行只有三个字段,所以只引用到了 $3
。除此之外另一个这里没有出现的 $0
,它表示引用当前记录(当前行)的全部内容。
- 将第二行的以点为分段的字段换成以空格为分隔:
1 |
|
说明:这里的 -F
参数,前面已经介绍过,它是用来预先指定待处理记录的字段分隔符。我们需要注意的是除了指定 OFS
我们还可以在 print
语句中直接打印特殊符号如这里的 \t
,print 打印的非变量内容都需要用""一对引号包围起来。上面另一个版本,展示了实现预先指定变量分隔符的另一种方式,即使用 BEGIN
,就这个表达式指示了,其后的动作将在所有动作之前执行,这里是 FS
赋值了新的 .
点号代替默认的空格。
注意:首先说明一点,我们在学习和使用 awk 的时候应该尽可能将其作为一门程序语言来理解,这样将会使你学习起来更容易,所以初学阶段在练习 awk
时应该尽量按照我那样的方式分多行按照一般程序语言的换行和缩进来输入,而不是全部写到一行(当然这在你熟练了之后是没有任何问题的)。
内置变量
变量名 | 说明 |
---|---|
FILENAME |
当前输入文件名,若有多个文件,则只表示第一个。如果输入是来自标准输入,则为空字符串 |
$0 |
当前记录的内容 |
$N |
N 表示字段号,最大值为NF 变量的值 |
FS |
字段分隔符,由正则表达式表示,默认为空格 |
RS |
输入记录分隔符,默认为 \n ,即一行为一个记录 |
NF |
当前记录字段数 |
NR |
已经读入的记录数 |
FNR |
当前输入文件的记录数,请注意它与 NR 的区别 |
OFS |
输出字段分隔符,默认为空格 |
ORS |
输出记录分隔符,默认为 \n |
软件安装
apt 包管理介绍
当你在执行安装操作时,首先 apt-get
工具会在本地的一个数据库中搜索关于 xxx
软件的相关信息,并根据这些信息在相关的服务器上下载软件安装,这里大家可能会一个疑问:既然是在线安装软件,为啥会在本地的数据库中搜索?要解释这个问题就得提到几个名词了:
- 软件源镜像服务器
- 软件源
我们需要定期从服务器上下载一个软件包列表,使用 sudo apt-get update
命令来保持本地的软件包列表是最新的(有时你也需要手动执行这个操作,比如更换了软件源),而这个表里会有软件依赖信息的记录,对于软件依赖,我举个例子:我们安装 xxx
软件的时候,而这个软件需要 libgc1c2
这个软件包才能正常工作,这个时候 apt-get
在安装软件的时候会一并替我们安装了,以保证 xxx
能正常的工作。
apt-get
apt-get
是用于处理 apt
包的公用程序集,我们可以用它来在线安装、卸载和升级软件包等,下面列出一些 apt-get
包含的常用的一些工具:
工具 | 说明 |
---|---|
install |
其后加上软件包名,用于安装一个软件包 |
update |
从软件源镜像服务器上下载/更新用于更新本地软件源的软件包列表 |
upgrade |
升级本地可更新的全部软件包,但存在依赖问题时将不会升级,通常会在更新之前执行一次 update |
dist-upgrade |
解决依赖关系并升级(存在一定危险性) |
remove |
移除已安装的软件包,包括与被移除软件包有依赖关系的软件包,但不包含软件包的配置文件 |
autoremove |
移除之前被其他软件包依赖,但现在不再被使用的软件包 |
purge |
与 remove 相同,但会完全移除软件包,包含其配置文件 |
clean |
移除下载到本地的已经安装的软件包,默认保存在 /var/cache/apt/archives/ |
autoclean |
移除已安装的软件的旧版本软件包 |
下面是一些apt-get
常用的参数:
参数 | 说明 |
---|---|
-y |
自动回应是否安装软件包的选项,在一些自动化安装脚本中使用这个参数将十分有用 |
-s |
模拟安装 |
-q |
静默安装方式,指定多个 q 或者 -q=# ,# 表示数字,用于设定静默级别,这在你不想要在安装软件包时屏幕输出过多时很有用 |
-f |
修复损坏的依赖关系 |
-d |
只下载不安装 |
--reinstall |
重新安装已经安装但可能存在问题的软件包 |
--install-suggests |
同时安装 APT 给出的建议安装的软件包 |
安装软件包
关于安装,如前面演示的一样你只需要执行 apt-get install <packagename>
即可,除了这一点,你还应该掌握的是如何重新安装软件包。
很多时候我们需要重新安装一个软件包,比如你的系统被破坏,或者一些错误的配置导致软件无法正常工作。你可以使用如下方式重新安装:
1 |
|
在不知道软件包完整名的时候进行安装,通常我们使用 Tab
键补全软件包名。同时也可以利用正则表达式匹配软件包名进行批量安装。
软件升级
1 |
|
软件卸载
1 |
|
或者,你可以执行
1 |
|
软件搜索
当自己刚知道了一个软件,想下载使用,需要确认软件仓库里面有没有,就需要用到搜索功能了,命令如下:
1 |
|
apt-cache
命令则是针对本地数据进行相关操作的工具,search
顾名思义在本地的数据库中寻找有关 softname1
,softname2
相关软件的信息。
dpkg 使用
dpkg 介绍
在网络上见到以deb
形式打包的软件包,就需要使用dpkg
命令来安装。
dpkg
常用参数介绍:
参数 | 说明 |
---|---|
-i |
安装指定 deb 包 |
-R |
后面加上目录名,用于安装该目录下的所有 deb 安装包 |
-r |
remove,移除某个已安装的软件包 |
-I |
显示 deb 包文件的信息 |
-s |
显示已安装软件的信息 |
-S |
搜索已安装的软件包 |
-L |
显示已安装软件包的目录信息 |
软件安装
1 |
|
如果这个包还额外依赖了一些软件包,这意味着,如果主机目前没有这些被依赖的软件包,直接使用 dpkg 安装可能会存在一些问题,因为dpkg
并不能为你解决依赖关系。
我们将如何解决这个错误呢?这就要用到apt-get
了,使用它的-f
参数了,修复依赖关系的安装
1 |
|
查看已安装软件包的安装目录
如果你在纠结到底 linux 将软件安装到了什么地方,那么很幸运你将可以通过dpkg
找到答案
使用dpkg -L
查看deb
包目录信息
1 |
|
二进制文件安装
对应文件下载下来后将对应的二进制包解压到合适目录,之后将包含可执行的主程序文件的目录添加进PATH
环境变量即可。
进程管理
并且每个终端或者说 bash 只能管理当前终端中的 job,不能管理其他终端中的 job。比如我当前存在两个 bash 分别为 bash1、bash2,bash1 只能管理其自己里面的 job 并不能管理 bash2 里面的 job
我们都知道当一个进程在前台运作时我们可以用 ctrl + c
来终止它,但是若是在后台的话就不行了。
我们可以通过 &
这个符号,让我们的命令在后台中运行:
1 |
|
图中所显示的 [1] 236
分别是该 job 的 job number 与该进程的 PID,而最后一行的 Done 表示该命令已经在后台执行完毕。
我们还可以通过 ctrl + z
使我们的当前工作停止并丢到后台中去
被停止并放置在后台的工作我们可以使用这个命令来查看:
1 |
|
其中第一列显示的为被放置后台 job 的编号,而第二列的 +
表示最近(刚刚、最后)被放置后台的 job,同时也表示预设的工作,也就是若是有什么针对后台 job 的操作,首先对预设的 job,-
表示倒数第二(也就是在预设之前的一个)被放置后台的工作,倒数第三个(再之前的)以后都不会有这样的符号修饰,第三列表示它们的状态,而最后一列表示该进程执行的命令。
我们可以通过这样的一个命令将后台的工作拿到前台来:
1 |
|
之前我们通过 ctrl + z
使得工作停止放置在后台,若是我们想让其在后台运作我们就使用这样一个命令:
1 |
|
既然有方法将被放置在后台的工作提至前台或者让它从停止变成继续运行在后台,当然也有方法删除一个工作,或者重启等等。
1 |
|
其中常用的有这些信号值
信号值 | 作用 |
---|---|
-1 | 重新读取参数运行,类似与 restart |
-2 | 如同 ctrl+c 的操作退出 |
-9 | 强制终止该任务 |
-15 | 正常的方式终止该任务 |
若是在使用 kill +信号值然后直接加 pid,你将会对 pid 对应的进程进行操作。
若是在使用 kill+信号值然后%jobnumber
,这时所操作的对象是 job,这个数字就是就当前 bash 中后台的运行的 job 的 ID。
进程的查看
Linux下可以使用top
来实时的查看进程状态,以及一些系统信息,于此也可以通过ps
静态查看当前的进程信息,同时我们还可以使用 pstree
来查看当前活跃进程的树形结构。
top 是一个在前台执行的程序,所以执行后便进入到这样的一个交互界面,正是因为交互界面我们才可以实时的获取到系统与进程的信息。在交互界面中我们可以通过一些指令来操作和筛选。在此之前我们先来了解显示了哪些信息。
我们看到 top 显示的第一排,
内容 | 解释 |
---|---|
top | 表示当前程序的名称 |
11:05:18 | 表示当前的系统的时间 |
up 8 days,17:12 | 表示该机器已经启动了多长时间 |
1 user | 表示当前系统中只有一个用户 |
load average: 0.29,0.20,0.25 | 分别对应 1、5、15 分钟内 cpu 的平均负载 |
load average 在 wikipedia 中的解释是 the system load is a measure of the amount of work that a computer system is doing 也就是对当前 CPU 工作量的度量,具体来说也就是指运行队列的平均长度,也就是等待 CPU 的平均进程数相关的一个计算值。
我们该如何看待这个 load average 数据呢?
假设我们的系统是单 CPU、单内核的,把它比喻成是一条单向的桥,把 CPU 任务比作汽车。
- load = 0 的时候意味着这个桥上并没有车,cpu 没有任何任务;
- load < 1 的时候意味着桥上的车并不多,一切都还是很流畅的,cpu 的任务并不多,资源还很充足;
- load = 1 的时候就意味着桥已经被车给占满了,没有一点空隙,cpu 已经在全力工作了,所有的资源都被用完了,当然还好,这还在能力范围之内,只是有点慢而已;
- load > 1 的时候就意味着不仅仅是桥上已经被车占满了,就连桥外都被占满了,cpu 已经在全力工作,系统资源的用完了,但是还是有大量的进程在请求,在等待。若是这个值大于 2 表示进程请求超过 CPU 工作能力的 2 倍。而若是这个值大于 5 说明系统已经在超负荷运作了。
这是单个 CPU 单核的情况,而实际生活中我们需要将得到的这个值除以我们的核数来看。我们可以通过以下的命令来查看 CPU 的个数与核心数:
1 |
|
通过上面的指数我们可以得知 load 的临界值为 1 ,但是在实际生活中,比较有经验的运维或者系统管理员会将临界值定为 0.7。这里的指数都是除以核心数以后的值,不要混淆了
- 若是 load < 0.7 并不会去关注他;
- 若是 0.7< load < 1 的时候我们就需要稍微关注一下了,虽然还可以应付但是这个值已经离临界不远了;
- 若是 load = 1 的时候我们就需要警惕了,因为这个时候已经没有更多的资源的了,已经在全力以赴了;
- 若是 load > 5 的时候系统已经快不行了,这个时候你需要加班解决问题了
通常我们都会先看 15 分钟的值来看这个大体的趋势,然后再看 5 分钟的值对比来看是否有下降的趋势。
查看 busybox 的代码可以知道,数据是每 5 秒钟就检查一次活跃的进程数,然后计算出该值,然后 load 从 /proc/loadavg
中读取的。而这个 load 的值是如何计算的呢,这是 load 的计算的源码
1 |
|
有兴趣的朋友可以研究一下,是如何计算的。代码中的后面这部分相当于它的计算公式。
我们回归正题,来看 top 的第二行数据,基本上第二行是进程的一个情况统计:
内容 | 解释 |
---|---|
Tasks: 26 total | 进程总数 |
1 running | 1 个正在运行的进程数 |
25 sleeping | 25 个睡眠的进程数 |
0 stopped | 没有停止的进程数 |
0 zombie | 没有僵尸进程数 |
来看 top 的第三行数据,这一行基本上是 CPU 的一个使用情况的统计了:
内容 | 解释 |
---|---|
Cpu(s): 1.0%us |
用户空间进程占用 CPU 百分比 |
1.0% sy |
内核空间运行占用 CPU 百分比 |
0.0%ni |
用户进程空间内改变过优先级的进程占用 CPU 百分比 |
97.9%id |
空闲 CPU 百分比 |
0.0%wa |
等待输入输出的 CPU 时间百分比 |
0.1%hi |
硬中断(Hardware IRQ)占用 CPU 的百分比 |
0.0%si |
软中断(Software IRQ)占用 CPU 的百分比 |
0.0%st |
(Steal time) 是 hypervisor 等虚拟服务中,虚拟 CPU 等待实际 CPU 的时间的百分比 |
CPU 利用率是对一个时间段内 CPU 使用状况的统计,通过这个指标可以看出在某一个时间段内 CPU 被占用的情况,而 Load Average 是 CPU 的 Load,它所包含的信息不是 CPU 的使用率状况,而是在一段时间内 CPU 正在处理以及等待 CPU 处理的进程数情况统计信息,这两个指标并不一样。
来看 top 的第四行数据,这一行基本上是内存的一个使用情况的统计了:
内容 | 解释 |
---|---|
8176740 total | 物理内存总量 |
8032104 used | 使用的物理内存总量 |
144636 free | 空闲内存总量 |
313088 buffers | 用作内核缓存的内存量 |
注意:
系统中可用的物理内存最大值并不是 free 这个单一的值,而是 free + buffers + swap 中的 cached 的和。
来看 top 的第五行数据,这一行基本上是交换区的一个使用情况的统计了:
内容 | 解释 |
---|---|
total | 交换区总量 |
used | 使用的交换区总量 |
free | 空闲交换区总量 |
cached | 缓冲的交换区总量,内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖 |
再下面就是进程的一个情况了
列名 | 解释 |
---|---|
PID | 进程 id |
USER | 该进程的所属用户 |
PR | 该进程执行的优先级 priority 值 |
NI | 该进程的 nice 值 |
VIRT | 该进程任务所使用的虚拟内存的总数 |
RES | 该进程所使用的物理内存数,也称之为驻留内存数 |
SHR | 该进程共享内存的大小 |
S | 该进程进程的状态: S=sleep R=running Z=zombie |
%CPU | 该进程 CPU 的利用率 |
%MEM | 该进程内存的利用率 |
TIME+ | 该进程活跃的总时间 |
COMMAND | 该进程运行的名字 |
注意:
NICE 值叫做静态优先级,是用户空间的一个优先级值,其取值范围是 -20 至 19。这个值越小,表示进程”优先级”越高,而值越大“优先级”越低。nice 值中的 -20 到 19,中 -20 优先级最高, 0 是默认的值,而 19 优先级最低。
PR 值表示 Priority 值叫动态优先级,是进程在内核中实际的优先级值,进程优先级的取值范围是通过一个宏定义的,这个宏的名称是 MAX_PRIO
,它的值为 140。Linux 实际上实现了 140 个优先级范围,取值范围是从 0-139
,这个值越小,优先级越高。而这其中的 0-99
是实时进程的值,而 100-139
是给用户的。
其中 PR 中的 100 to 139
值部分有这么一个对应 PR = 20 + (-20 to +19)
,这里的 -20 to +19
便是 nice 值,所以说两个虽然都是优先级,而且有千丝万缕的关系,但是他们的值,他们的作用范围并不相同。
VIRT 任务所使用的虚拟内存的总数,其中包含所有的代码,数据,共享库和被换出 swap 空间的页面等所占据空间的总数。
在上文我们曾经说过 top 是一个前台程序,所以是一个可以交互的:
常用交互命令 | 解释 |
---|---|
q | 退出程序 |
I | 切换显示平均负载和启动时间的信息 |
P | 根据 CPU 使用百分比大小进行排序 |
M | 根据驻留内存大小进行排序 |
i | 忽略闲置和僵死的进程,这是一个开关式命令 |
k | 终止一个进程,系统提示输入 PID 及发送的信号值。一般终止进程用 15 信号,不能正常结束则使用 9 信号。安全模式下该命令被屏蔽。 |
好好的利用 top 能够很有效的帮助我们观察到系统的瓶颈所在,或者是系统的问题所在。
ps的使用
我们来总体了解下会出现哪些信息给我们,这些信息又代表着什么(更多的 keywords 大家可以通过 man ps
了解)。
内容 | 解释 |
---|---|
F |
进程的标志(process flags),当 flags 值为 1 则表示此子程序只是 fork 但没有执行 exec,为 4 表示此程序使用超级管理员 root 权限 |
USER |
进程的拥有用户 |
PID |
进程的 ID |
PPID |
其父进程的 PID |
SID |
session 的 ID |
TPGID |
前台进程组的 ID |
%CPU |
进程占用的 CPU 百分比 |
%MEM |
占用内存的百分比 |
NI |
进程的 NICE 值 |
VSZ |
进程使用虚拟内存大小 |
RSS |
驻留内存中页的大小 |
TTY |
终端 ID |
S or STAT |
进程状态 |
WCHAN |
正在等待的进程资源 |
START |
启动进程的时间 |
TIME |
进程消耗 CPU 的时间 |
COMMAND |
命令的名称和参数 |
TPGID栏写着-1 的都是没有控制终端的进程,也就是守护进程
STAT表示进程的状态,而进程的状态有很多,如下表所示
状态 | 解释 |
---|---|
R |
Running.运行中 |
S |
Interruptible Sleep.等待调用 |
D |
Uninterruptible Sleep.不可中断睡眠 |
T |
Stoped.暂停或者跟踪状态 |
X |
Dead.即将被撤销 |
Z |
Zombie.僵尸进程 |
W |
Paging.内存交换 |
N |
优先级低的进程 |
< |
优先级高的进程 |
s |
进程的领导者 |
L |
锁定状态 |
l |
多线程状态 |
+ |
前台进程 |
其中的 D 是不能被中断睡眠的状态,处在这种状态的进程不接受外来的任何 signal,所以无法使用 kill 命令杀掉处于 D 状态的进程,无论是
kill
,kill -9
还是kill -15
,一般处于这种状态可能是进程 I/O 的时候出问题了。
ps 工具有许多的参数,下面给大家解释部分常用的参数。
使用 -l
参数可以显示自己这次登录的 bash 相关的进程信息罗列出来:
1 |
|
相对来说我们更加常用下面这个命令,他将会罗列出所有的进程信息:
1 |
|
若是查找其中的某个进程的话,我们还可以配合着 grep
和正则表达式一起使用:
1 |
|
此外我们还可以查看时,将连同部分的进程呈树状显示出来:
1 |
|
当然如果你觉得使用这样的此时没有把你想要的信息放在一起,我们也可以是用这样的命令,来自定义我们所需要的参数显示:
1 |
|
这是一个简单而又实用的工具,想要更灵活的使用,想要知道更多的参数我们可以使用 man 来获取更多相关的信息。
pstree的使用
通过 pstree
可以很直接的看到相同的进程数量,最主要的还是我们可以看到所有进程之间的相关性。
1 |
|
1 |
|
参数选择 | 解释 |
---|---|
-A | 程序树之间以 ASCII 字符连接 |
-p | 同时列出每个 process 的 PID |
-u | 同时列出每个 process 的所属账户名称 |
kill指令的使用
我们来回顾一下,当一个进程结束的时候或者要异常结束的时候,会向其父进程返回一个或者接收一个 SIGHUP 信号而做出的结束进程或者其他的操作,这个 SIGHUP 信号不仅可以由系统发送,我们可以使用 kill
来发送这个信号来操作进程的结束或者重启等等。
上节课程我们使用 kill
命令来管理我们的一些 job,这节课我们将尝试用 kill
来操作下一些不属于 job 范畴的进程,直接对 pid 下手。
1 |
|
进程执行顺序
我们在使用 ps 命令的时候可以看到大部分的进程都是处于休眠的状态,如果这些进程都被唤醒,那么该谁最先享受 CPU 的服务,后面的进程又该是一个什么样的顺序呢?进程调度的队列又该如何去排列呢?
当然就是靠该进程的优先级值来判定进程调度的优先级,而优先级的值就是上文所提到的 PR 与 nice 来控制与体现了
而 nice 的值我们是可以通过 nice 命令来修改的,而需要注意的是 nice 值可以调整的范围是 -20 ~ 19
,其中 root 有着至高无上的权力,既可以调整自己的进程也可以调整其他用户的程序,并且是所有的值都可以用,而普通用户只可以调制属于自己的进程,并且其使用的范围只能是 0 ~ 19
,因为系统为了避免一般用户抢占系统资源而设置的一个限制
1 |
|
我们还可以用 renice 来修改已经存在的进程的优先级,同样因为权限的原因在实验环境中无法尝试。
1 |
|
日志系统
日志是一个系统管理员,一个运维人员,甚至是开发人员不可或缺的东西,系统用久了偶尔也会出现一些错误,我们需要日志来给系统排错,在一些网络应用服务不能正常工作的时候,我们需要用日志来做问题定位,日志还是过往时间的记录本,我们可以通过它知道我们是否被不明用户登录过等等。
在 Linux 中大部分的发行版都内置使用 syslog 系统日志,那么通过前期的课程我们了解到常见的日志一般存放在 /var/log
中,我们来看看其中有哪些日志
根据图中所显示的日志,我们可以根据服务对象粗略的将日志分为两类
- 系统日志
- 应用日志
系统日志主要是存放系统内置程序或系统内核之类的日志信息如 alternatives.log
、btmp
等等,应用日志主要是我们装的第三方应用所产生的日志如 tomcat7
、apache2
等等。
接下来我们来看看常见的系统日志有哪些,他们都记录了怎样的信息
日志名称 | 记录信息 |
---|---|
alternatives.log | 系统的一些更新替代信息记录 |
apport.log | 应用程序崩溃信息记录 |
apt/history.log | 使用 apt-get 安装卸载软件的信息记录 |
apt/term.log | 使用 apt-get 时的具体操作,如 package 的下载、打开等 |
auth.log | 登录认证的信息记录 |
boot.log | 系统启动时的程序服务的日志信息 |
btmp | 错误的信息记录 |
Consolekit/history | 控制台的信息记录 |
dist-upgrade | dist-upgrade 这种更新方式的信息记录 |
dmesg | 启动时,显示屏幕上内核缓冲信息,与硬件有关的信息 |
dpkg.log | dpkg 命令管理包的日志。 |
faillog | 用户登录失败详细信息记录 |
fontconfig.log | 与字体配置有关的信息记录 |
kern.log | 内核产生的信息记录,在自己修改内核时有很大帮助 |
lastlog | 用户的最近信息记录 |
wtmp | 登录信息的记录。wtmp 可以找出谁正在进入系统,谁使用命令显示这个文件或信息等 |
syslog | 系统信息记录 |
而在本实验环境中没有 apport.log 是因为 apport 这个应用程序需要读取一些内核的信息来收集判断其他应用程序的信息,从而记录应用程序的崩溃信息。而在本实验环境中我们没有这个权限,所以将 apport 从内置应用值剔除,自然而然就没有它的日志信息了。
只闻其名,不见其人,我们并不能明白这些日志记录的内容。首先我们来看 alternatives.log
中的信息,在本实验环境中没有任何日志输出是因为刚刚启动的系统中并没有任何的更新迭代。我可以看看从其他地方截取过来的内容
1 |
|
我们可以从中得到的信息有程序作用,日期,命令,成功与否的返回码。
我们用这样的命令来看看 auth.log
中的信息:
1 |
|
我们可以从中得到的信息有日期与 ip 地址的来源以及的用户与工具。
在 /var/log/apt
文件夹中有两个日志文件 history.log
与 term.log
,两个日志文件的区别在于 history.log
主要记录了进行了哪个操作,相关的依赖有哪些,而 term.log
则是较为具体的一些操作,主要就是下载包,打开包,安装包等等的细节操作。
如果是刚刚开启的新系统,那么按理说这些日志应该都是空的。
1 |
|
但是在实验环境中因为是启动的我们定制后的环境,所以两个日志中还残留了配置镜像的记录。可以先删除这两个文件然后再执行新的安装命令。
1 |
|
我们来安装 git 这个程序,因为实验环境里已经预装了 git,所以这里真正执行的操作是一个更新的操作,但这并不影响。
1 |
|
成功的执行之后我们再来查看两个日志的内容变化:
其他的日志格式也都类似于之前我们所查看的日志,主要便是时间,操作。而这其中有两个比较特殊的日志,其查看的方式比较与众不同,因为这两个日志并不是 ASCII 文件而是被编码成了二进制文件,所以我们并不能直接使用 less、cat、more 这样的工具来查看,这两个日志文件是 wtmp,lastlog
我们查看的方法是使用 last 与 lastlog 工具来提取其中的信息
关于这两个工具的更深入使用我们可以使用前面的学习过的 man 来查看
这些日志是如何产生的?通过上面的例子我们可以看出大部分的日志信息似乎格式都很类似,并且都出现在这个文件夹中。
这样的实现可以通过两种方式:
- 一种是由软件开发商自己来自定义日志格式然后指定输出日志位置;
- 一种方式就是 Linux 提供的日志服务程序,而我们这里系统日志是通过 syslog 来实现,提供日志管理服务。
syslog 是一个系统日志记录程序,在早期的大部分 Linux 发行版都是内置 syslog,让其作为系统的默认日志收集工具,虽然随着时代的进步与发展,syslog 已经年老体衰跟不上时代的需求,所以他被 rsyslog 所代替了,较新的 Ubuntu、Fedora 等等都是默认使用 rsyslog 作为系统的日志收集工具
rsyslog 的全称是 rocket-fast system for log,它提供了高性能,高安全功能和模块化设计。rsyslog 能够接受各种各样的来源,将其输入,输出的结果到不同的目的地。rsyslog 可以提供超过每秒一百万条消息给目标文件。
这样能实时收集日志信息的程序是有其守护进程的,如 rsyslog 的守护进程便是 rsyslogd
因为一些原因本实验环境中默认并没有打开这个服务,我们可以手动开启这项服务,然后来查看
1 |
|
既然它是一个服务,那么它便是可以配置,为我们提供一些我们自定义的服务
首先我们来看 rsyslog 的配置文件是什么样子的,而 rsyslog 的配置文件有两个,
- 一个是
/etc/rsyslog.conf
- 一个是
/etc/rsyslog.d/50-default.conf
。
第一个主要是配置的环境,也就是 rsyslog 加载什么模块,文件的所属者等;而第二个主要是配置的 Filter Conditions
1 |
|
也不知道他在写什么,我们还是来看看 rsyslog 的结构框架,数据流的走向吧。
通过这个简单的流程图我们可以知道 rsyslog 主要是由 Input、Output、Parser 这样三个模块构成的,并且了解到数据的简单走向,首先通过 Input module 来收集消息,然后将得到的消息传给 Parser module,通过分析模块的层层处理,将真正需要的消息传给 Output module,然后便输出至日志文件中。
上文提到过 rsyslog 号称可以提供超过每秒一百万条消息给目标文件,怎么只是这样简单的结构。我们可以通过下图来做更深入的了解
(图片来源于http://www.rsyslog.com/doc/queues_analogy.html)
Rsyslog 架构如图中所示,从图中我们可以很清楚的看见,rsyslog 还有一个核心的功能模块便是 Queue,也正是因为它才能做到如此高的并发。
第一个模块便是 Input,该模块的主要功能就是从各种各样的来源收集 messages,通过这些接口实现:
接口名 | 作用 |
---|---|
im3195 | RFC3195 Input Module |
imfile | Text File Input Module |
imgssapi | GSSAPI Syslog Input Module |
imjournal | Systemd Journal Input Module |
imklog | Kernel Log Input Module |
imkmsg | /dev/kmsg Log Input Module |
impstats | Generate Periodic Statistics of Internal Counters |
imptcp | Plain TCP Syslog |
imrelp | RELP Input Module |
imsolaris | Solaris Input Module |
imtcp | TCP Syslog Input Module |
imudp | UDP Syslog Input Module |
imuxsock | Unix Socket Input |
而 Output 中也有许多可用的接口,可以通过 man 或者官方的文档查看
而这些模块接口的使用需要通过 $ModLoad 指令来加载,那么返回上文的图中,配置生效的头两行可以看懂了,默认加载了 imklog、imuxsock 这两个模块
在配置中 rsyslog 支持三种配置语法格式:
- sysklogd
- legacy rsyslog
- RainerScript
sysklogd 是老的简单格式,一些新的语法特性不支持。而 legacy rsyslog 是以 dollar 符($)开头的语法,在 v6 及以上的版本还在支持,就如上文所说的 $ModLoad
还有一些插件和特性只在此语法下支持。而以 $
开头的指令是全局指令,全局指令是 rsyslogd 守护进程的配置指令,每行只能有一个指令。 RainnerScript 是最新的语法。在官网上 rsyslog 大多推荐这个语法格式来配置
老的语法格式(sysklogd & legacy rsyslog)是以行为单位。新的语法格式(RainnerScript)可以分割多行。
注释有两种语法:
- 井号 #
- C-style
/* .. */
执行顺序: 指令在 rsyslog.conf 文件中是从上到下的顺序执行的。
模板是 rsyslog 一个重要的属性,它可以控制日志的格式,支持类似 template() 语句的基于 string 或 plugin 的模板,通过它我们可以自定义日志格式。
legacy 格式使用 $template 的语法,不过这个在以后要移除,所以最好使用新格式 template():,以免未来突然不工作了也不知道为什么
模板定义的形式有四种,适用于不同的输出模块,一般简单的格式,可以使用 string 的形式,复杂的格式,建议使用 list 的形式,使用 list 的形式,可以使用一些额外的属性字段(property statement)
如果不指定输出模板,rsyslog 会默认使用 RSYSLOG_DEFAULT。若想更深入的学习可以查看官方文档
了解了 rsyslog 环境的配置文件之后,我们看向 /etc/rsyslog.d/50-default.conf
这个配置文件,这个文件中主要是配置的 Filter Conditions,也就是我们在流程图中所看见的 Parser & Filter Engine
,它的名字叫 Selectors 是过滤 syslog 的传统方法,他主要由两部分组成,facility
与 priority
,其配置格式如下:
1 |
|
其中一个 priority 可以指定多个 facility,多个 facility 之间使用逗号 ,
分割开
rsyslog 通过 Facility 的概念来定义日志消息的来源,以便对日志进行分类,Facility 的种类有:
类别 | 解释 |
---|---|
kern | 内核消息 |
user | 用户信息 |
邮件系统消息 | |
daemon | 系统服务消息 |
auth | 认证系统 |
authpriv | 权限系统 |
syslog | 日志系统自身消息 |
cron | 计划安排 |
news | 新闻信息 |
local0~7 | 由自定义程序使用 |
而另外一部分 priority 也称之为 serverity level,除了日志的来源以外,对统一源产生日志消息还需要进行优先级的划分,而优先级的类别有以下几种:
类别 | 解释 |
---|---|
emergency | 系统已经无法使用了 |
alert | 必须立即处理的问题 |
critical | 很严重了 |
error | 错误 |
warning | 警告信息 |
notice | 系统正常,但是比较重要 |
informational | 正常 |
debug | debug 的调试信息 |
panic | 很严重但是已淘汰不常用 |
none | 没有优先级,不记录任何日志消息 |
我们来看看系统中的配置
1 |
|
这里的意思是 auth 与 authpriv 的所有优先级的信息全都输出于 /var/log/auth.log
日志中
而其中有类似于这样的配置信息意思有细微的差别
1 |
|
-
代表异步写入,也就是日志写入时不需要等待系统缓存的同步,也就是日志还在内存中缓存也可以继续写入无需等待完全写入硬盘后再写入。通常用于写入数据比较大时使用。
到此我们对 rsyslog 的配置就有了一定的了解,若想更深入学习模板,队列的高级应用,大家可去查看官网的文档,需要注意的是 rsyslog 每个版本之间差异化比较大,学习之前先查看自己所使用的版本,再去查看相关的文档
与日志相关的还有一个还有常用的命令 logger
,logger
是一个 shell 命令接口,可以通过该接口使用 Syslog 的系统日志模块,还可以从命令行直接向系统日志文件写入信息。
1 |
|
从图中我们可以看到我们成功的将 ping 的信息写入了 syslog 中,格式也就是使用的 rsyslog 的默认模板
我们可以通过 man 来查看 logger 的其他用法,
参数 | 内容 |
---|---|
-i | 在每行都记录进程 ID |
-t | 添加 tag 标签 |
-p | 设置日志的 facility 与 priority |
日志转储
在本地的机器中每天都有成百上千条日志被写入文件中,更别说是我们的服务器,每天都会有数十兆甚至更多的日志信息被写入文件中,如果是这样的话,每天看着我们的日志文件不断的膨胀,那岂不是要占用许多的空间,所以有个叫 logrotate 的东西诞生了。
logrotate 程序是一个日志文件管理工具。用来把旧的日志文件删除,并创建新的日志文件。我们可以根据日志文件的大小,也可以根据其天数来切割日志、管理日志,这个过程又叫做“转储”。
大多数 Linux 发行版使用 logrotate 或 newsyslog 对日志进行管理。logrotate 程序不但可以压缩日志文件,减少存储空间,还可以将日志发送到指定 E-mail,方便管理员及时查看日志。
显而易见,logrotate 是基于 CRON 来运行的,其脚本是 /etc/cron.daily/logrotate;同时我们可以在 /etc/logrotate
中找到其配置文件
1 |
|
这其中的具体意思是什么呢?
1 |
|
当然在 /etc/logrotate.d/ 中有各项应用的 logrotate 配置,还有更多的配置参数,大家可以使用 man 查看,如按文件大小转储,按当前时间格式命名等等参数配置。