Linux Administration

Stone大约 220 分钟

Linux Administration

概述

对于日常办公使用的桌面电脑,大部分都是使用 Windows 操作系统;而对于提供系统应用的服务器,则大部分都是使用 Linux 操作系统。简单来说,Linux 就是一个操作系统,且是一个开源的操作系统。Linux 有很多发行版本,之前常用的免费发行版是 CentOS(Community Enterprise Operating System),Red Hat 改变对 CentOS 的发布策略后,可以使用 Rocky Linux 替代。

安装

作为服务器操作系统,一般在服务器上安装 Linux。学习时没有服务器怎么办,可以使用虚拟化软件来模拟服务器。常用的虚拟化软件有 VMware Workstation,Oracle VM VirtualBox。这里使用 VMware Workstation。

创建虚拟机

官方网站open in new window下载并安装 VMware Workstation。安装后打开,界面如下,点击 “创建新的虚拟机”:

image-20230622110751594

启动 “新建虚拟机向导” 来创建虚拟机,选择 “典型”,然后 “下一步”:

image-20230622112918521

选择 “稍后安装操作系统”,然后 “下一步”:

image-20230622111316788

客户机操作系统选择 “Linux”,版本选择 “CentOS 7 64 位”,然后 “下一步”:

image-20230622115028487

指定虚拟机名称和位置,然后 “下一步”:

image-20230622115121670

指定 “最大磁盘大小”,选择 “将虚拟磁盘存储为单个文件”,然后 “下一步”:

image-20230622112640394

确认无误,点击 “完成”。

image-20230622115145936

可以看到创建的虚拟机了。

image-20230622115212086

安装 CentOS

官方网站open in new window下载安装文件,也可以在阿里云镜像open in new window下载,这里下载 ISO 映像文件:CentOS-7-x86_64-DVD-2009.isoopen in new window

在 VMware Workstation 的 CentOS7 页面点击 “编辑虚拟机设置”,将内存修改为 2 GB:

image-20230622120430058

选择下载的 ISO 映像文件后点击 “确定”:

image-20230622120747737

然后点击 “开启此虚拟机”:

image-20230622121023397

选择 “Install CentOS 7”,回车进行安装:

image-20230622121213121

保持默认语言 “English”,点击 “Continue”:

image-20230622121458482

点击 “DATE & TIME”,设置时区和日期时间:

image-20230622130056555

“Region” 选择 “Asia”,“City” 选择 “Shanghai”,设置日期和时间后,点击 “Done”:

image-20230622121845575

点击 “INSTALLATION DESTINATION”,设置安装位置:

image-20230622130245978

这里先使用默认值,点击 “Done”:

image-20230622130421119

点击 “NETWORK & HOST NAME”,设置网络:

image-20230622133649395

启用网络,自动获取到 IP 地址:192.168.92.128,并设置主机名,点击 “Done”:

image-20230622134012952

点击 “Begin Installation”:

image-20230622134216798

开始安装:

image-20230622130646211

安装完成,提示还需要完成一些配置:

image-20230622131017080

点击 “ROOT PASSWORD”,设置 root 账户密码,如果密码太简单,则需要点击两次 “Done” 进行确认:

image-20230622131237825

点击 “Finish configuration”,完成配置:

image-20230622131417895

点击 “Reboot” 进行重启:

image-20230622131655224

重启后,输入用户名 root 及其密码后进入命令行界面,就可以使用系统了。

image-20230622131945468

连接 CentOS

在 VMware Workstation 中直接使用 CentOS 很不方便,可以使用终端工具连接到 CentOS 进行使用。常用的终端工具有:PuTTY,XShell 以及 SecureCRT 等。

这里使用 SecureCRT,在官方网站open in new window下载并安装后,创建到 CentOS 虚拟机的连接。其中,“Hostname“ 为前面自动获取的 IP 地址,“Username“ 为 root,点击 “Connect”:

image-20230622135752752

点击 “Accept & Save” 接受并保存密钥:

image-20230622140141465

输入密码并勾选 “Save password”,点击 “OK”:

image-20230622140346121

可以看到已经连接到 CentOS,进入命令行界面:

image-20230622140440739

文件

本节主要介绍如何管理普通的目录和文件。

基础管理

在操作系统上,进行最多的工作就是管理目录和文件,包括创建,删除,修改,查看文件和目录。在 Linux 中一切皆文件,所有文件都在以 / 表示的根目录下。使用以下命令管理目录和文件。

tree

使用 tree 命令查看目录树。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install tree

查看系统一级目录:

[root@stone ~]# tree -L 1 /
/                           #根目录
├── bin -> usr/bin          #基本命令二进制文件
├── boot                    #引导程序文件
├── dev                     #设备文件
├── etc                     #配置文件
├── home                    #用户主目录
├── lib -> usr/lib          #库文件
├── lib64 -> usr/lib64      #库文件
├── media                   #用于挂载可移动存储设备
├── mnt                     #临时挂载文件系统的目录
├── opt                     #第三方软件或应用程序安装目录
├── proc                    #虚拟文件系统,包含系统和进程信息
├── root                    #root 用户的主目录
├── run                     #运行时状态文件
├── sbin -> usr/sbin        #系统管理二进制文件
├── srv                     #服务数据文件
├── sys                     #虚拟文件系统,用于访问和控制内核对象
├── tmp                     #临时文件
├── usr                     #应用程序、库文件和文档
└── var                     #可变数据

19 directories, 0 files

CentOS 的文件系统遵循 FHSopen in new window 标准。

提示:

  • 可以使用 Tab 键补全命令和目录。
  • 可以使用 man 命令查看其它命令的说明,例如 man tree,或者使用 tree --help

其中:

-L:指定目录最大深度,这里只显示 1 层。

ls

使用 lslist)命令查看目录和文件列表。

常用选项有:

选项含义
-a列出所有文件,包括隐藏文件(以 . 开头的文件)
-l以详细格式列出(一般使用别名:ll
-d列出目录信息
-h以可读方式显示文件大小
-i列出 Inode 节点索引号码
-r倒序列出
-R递归列出
-t按修改时间排列

查看当前目录下的所有目录和文件:

[root@stone ~]# ls -a   
.  ..  anaconda-ks.cfg  .bash_logout  .bash_profile  .bashrc  .cshrc  .tcshrc

查看指定目录下的所有目录和文件:

[root@stone ~]# ls -a /tmp/
.  ..  .font-unix  .ICE-unix  ks-script-i3ZLR4  .Test-unix  .X11-unix  .XIM-unix 

查看以 .bash 开头的所有文件:

[root@stone ~]# ls .bash*
.bash_logout  .bash_profile  .bashrc

提示:

使用通配符 *,匹配任意字符。

查看目录和文件详细信息:

[root@stone ~]# ls -la
dr-xr-x---.  3 root root  229 Jun 23 16:41 .
dr-xr-xr-x. 17 root root  224 Jun 22 20:39 ..
-rw-------.  1 root root 1227 Jun 22 20:40 anaconda-ks.cfg
-rw-------.  1 root root 1131 Jun 23 00:00 .bash_history
-rw-r--r--.  1 root root   18 Dec 29  2013 .bash_logout
-rw-r--r--.  1 root root  176 Dec 29  2013 .bash_profile
-rw-r--r--.  1 root root  176 Dec 29  2013 .bashrc
-rw-r--r--.  1 root root  100 Dec 29  2013 .cshrc
-rw-r--r--.  1 root root  129 Dec 29  2013 .tcshrc

其中:

  • 第1 列 -rw-r--r--:表示文件类型和权限
  • 第 2 列 1:表示链接数
  • 第 3 列 root:表示所属用户
  • 第 4 列 root:表示所属组
  • 第 5 列 129:表示大小
  • 第 6 列 Dec 29 2013:表示修改时间
  • 第 7 列 .tcshrc:表示文件名

pwd

使用 pwdprint work directory)命令查看当前所在目录:

[root@stone ~]# pwd
/root

cd

使用 cdchange directory)命令切换目录:

[root@stone ~]# cd /tmp/
[root@stone tmp]# pwd
/tmp

Linux 有一些特殊的目录名:

符号含义
.当前工作目录
..父目录
~用户主目录
-上个工作目录

切换到 root 用户主目录:

[root@stone ~]# cd ~
[root@stone ~]# pwd
/root

切换到父目录:

[root@stone ~]# cd ..
[root@stone /]# pwd
/

切换到上个工作目录:

[root@stone /]# cd -
/root
[root@stone ~]# pwd
/root

mkdir

使用 mkdirmake directory)命令创建目录:

[root@stone ~]# mkdir d1
[root@stone ~]# ls
anaconda-ks.cfg  d1

一次创建多个目录:

[root@stone ~]# mkdir d2 d3
[root@stone ~]# ls
anaconda-ks.cfg  d1  d2  d3

使用 -p 选项创建多级目录:

[root@stone ~]# mkdir -p d4/d5
[root@stone ~]# ls /root/d4/
d5

touch

使用 touch 命令创建文件:

[root@stone ~]# touch f1
[root@stone ~]# ls
anaconda-ks.cfg  d1  d2  d3  d4  f1

可以一次创建多个文件:

[root@stone ~]# touch f2 f3
[root@stone ~]# ls
anaconda-ks.cfg  d1  d2  d3  d4  f1  f2  f3

cp

使用 cpcopy)命令拷贝目录和文件。

常用选项有:

  • -r:递归拷贝目录
  • -a:递归拷贝目录,保留文件的属性和链接

拷贝文件:

[root@stone ~]# cp f1 f1.bak
[root@stone ~]# ls f1*
f1  f1.bak

拷贝目录:

[root@stone ~]# cp -r d1 d1.bak
[root@stone ~]# ls
anaconda-ks.cfg  d1  d1.bak  d2  d3  d4  f1  f1.bak  f2  f3

拷贝文件到目录:

[root@stone ~]# cp f1 d1/
[root@stone ~]# ls d1/
f1

拷贝目录,保留文件的属性和链接:

[root@stone ~]# cp -a /root /tmp

mv

使用 mvmove)命令移动或者重命名文件和目录。

重命名文件:

[root@stone ~]# ls f2*
f2
[root@stone ~]# mv f2 f2.bak
[root@stone ~]# ls f2*
f2.bak

重命名目录:

[root@stone ~]# ls -d d2*
d2
[root@stone ~]# mv d2 d2.bak
[root@stone ~]# ls -d d2*   
d2.bak

移动文件到目录:

[root@stone ~]# ls
anaconda-ks.cfg  d1  d1.bak  d2.bak  d3  d4  f1  f1.bak  f2.bak  f3
[root@stone ~]# mv f3 d3
[root@stone ~]# ls d3
f3

移动目录到目录:

[root@stone ~]# ls
anaconda-ks.cfg  d1  d1.bak  d2.bak  d3  d4  f1  f1.bak  f2.bak
[root@stone ~]# mv d4 d3
[root@stone ~]# ls d3
d4  f3
[root@stone ~]# ls
anaconda-ks.cfg  d1  d1.bak  d2.bak  d3  f1  f1.bak  f2.bak

rmdir

使用 rmdirremove directory)命令删除空目录:

[root@stone ~]# ls
anaconda-ks.cfg  d1  d2  d3  d4
[root@stone ~]# rmdir d1
[root@stone ~]# ls
anaconda-ks.cfg  d2  d3  d4

rm

使用 rm(remove)命令删除目录和文件。

删除文件:

[root@stone ~]# rm f2.bak
rm: remove regular empty file ‘f2.bak’? y

这里会提示你进行确认,实际上是使用了 alias 命令定义了 rm 命令的别名为 rm -i

[root@stone ~]# alias rm
alias rm='rm -i'

其中,-i 选项表示需要进行确认。可以使用 -f 选项强制删除而不需要确认。

[root@stone ~]# rm -f f1.bak

使用 -r 选项删除目录:

[root@stone ~]# rm -fr d3

一次性删除多个目录:

[root@stone ~]# rm -fr d1.bak d2.bak

chmod

使用 chmodchange mode)命令修改目录和文件的权限。

Linux 中的每一个文件(包括目录)都有 r(读)、w(写)、x(执行)三种权限,对于文件和目录,这三种权限的意义不一样,具体区别如下表:

权限文件目录
r读取文件内容只能读取目录中文件的文件名
w修改文件内容修改目录中的文件(添加,删除文件等)
x执行文件(针对可执行文件)进入目录

文件和目录的所有者可能是用户(user)、组(group)或者其他人(others),Linux 针对不同的所有者可以设置不同的权限,故每一个文件或者目录都有三组权限,分别为用户权限,组权限和其他人权限。

[root@stone ~]# ls -l f1
-rw-r--r--. 2 root root 0 Jun 22 22:14 f1
[root@stone ~]# ls -dl d1
drwxr-xr-x. 2 root root 16 Jun 22 22:21 d1

如上,其中 -rw-r--r-- 的第 1 位 - 表示文件,如果为 d 表示目录,第 2-4 位 rw- 表示用户权限,第 5-7 位 r-- 表示组权限,第 8-10 位 r-- 表示其他人权限。

chmod 中可以分别使用 u 表示用户,g 表示组,o 表示其他人,a 表示所有人,+ 表示增加权限,- 表示去掉权限,= 表示设置为该权限。

为所有人增加文件的执行权限:

[root@stone ~]# ls -l f1    
-rw-r--r--. 2 root root 0 Jun 22 22:14 f1
[root@stone ~]# chmod a+x f1
[root@stone ~]# ls -l f1    
-rwxr-xr-x. 2 root root 0 Jun 22 22:14 f1

权限可以采用三组八进制来表示,每一组内的字母对应的数值如下:

权限数值
r4
w2
x1
-(表示无权限)0

故字母表示的权限就可以换算成数字表示的权限了,如 -rw-r--r-- ,就可以换算成 644(4+2 4 4)。

修改文件的权限为 644

[root@stone ~]# ls -l f1    
-rwxr-xr-x. 2 root root 0 Jun 22 22:14 f1
[root@stone ~]# chmod 644 f1
[root@stone ~]# ls -l f1    
-rw-r--r--. 2 root root 0 Jun 22 22:14 f1

umask

使用 umask 命令设置权限掩码,用于指定新建文件或目录的默认权限。

[root@stone ~]# umask 
0022
[root@stone ~]# umask -S
u=rwx,g=rx,o=rx

对于 root 用户,权限掩码默认为 0022,表示对于组和其他人来说,是没有 w 权限的,那么

  • 对于新建目录,默认权限为 drwxrwxrwx - d----w--w- = drwxr-xr-x
  • 对于新建文件,默认权限为 -rw-rw-rw- - -----w--w- = -rw-r--r--

stat

使用 stat 命令查看目录和文件属性:

[root@stone ~]# stat d1
  File: ‘d1’
  Size: 16              Blocks: 0          IO Block: 4096   directory
Device: fd00h/64768d    Inode: 16784340    Links: 2
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2023-06-22 22:21:19.597090507 +0800
Modify: 2023-06-22 22:21:14.198090426 +0800
Change: 2023-06-22 22:21:14.198090426 +0800
 Birth: -
 
[root@stone ~]# stat f1
  File: ‘f1’
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 33575016    Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2023-06-22 22:16:40.781086339 +0800
Modify: 2023-06-22 22:14:19.422084225 +0800
Change: 2023-06-22 22:14:19.422084225 +0800
 Birth: -

各个属性的含义如下:

名称含义
Size目录或文件大小
InodeInode 编号,属性存储在 Inode 中
Links文件链接数
Access文件权限
Uid用户 ID
Gid组 ID
Access最近一次访问目录或文件的时间
Modify最近一次修改目录或文件内容的时间
Change最近一次改变目录或文件属性的时间

ln

使用 ln 命令创建链接,Linux 中的链接有两类:

  • 硬链接
    • 只能用于文件,不能用于目录,适用于不同用户对同一文件的访问。
    • 创建硬链接后文件链接数都增加 1。
    • 两个文件名对应同一个 Inode 节点和文件内容。
    • 删除一个文件名只是脱链一个文件,另一个还有效。
    • 使用命令 ln 创建硬链接。

创建硬链接:

[root@stone ~]# ln f1 f1_h
[root@stone ~]# ll f1*
-rw-r--r--. 2 root root 0 Jun 22 22:14 f1
-rw-r--r--. 2 root root 0 Jun 22 22:14 f1_h
[root@stone ~]# stat f1
  File: ‘f1’
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 33575016    Links: 2
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2023-06-22 22:16:40.781086339 +0800
Modify: 2023-06-22 22:14:19.422084225 +0800
Change: 2023-06-22 23:46:58.775167337 +0800
 Birth: -
[root@stone ~]# stat f1_h
  File: ‘f1_h’
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 33575016    Links: 2
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2023-06-22 22:16:40.781086339 +0800
Modify: 2023-06-22 22:14:19.422084225 +0800
Change: 2023-06-22 23:46:58.775167337 +0800
 Birth: -

可以看到这两个文件的 Inode 相同,Links 都为 2。

  • 软连接

    • 可以用于文件和目录,相当于 Windows 中的快捷方式。

    • 创建软链接后文件链接数保持不变。

    • 两个文件名对应 2 个 Inode 节点和文件内容。

    • 删除原始文件会导致空链接。

    • 使用命令 ln -s 创建软连接。

创建软连接:

[root@stone ~]# touch f2
[root@stone ~]# ln -s f2 f2_s
[root@stone ~]# ll f2*
-rw-r--r--. 1 root root 0 Jun 22 23:52 f2
lrwxrwxrwx. 1 root root 2 Jun 22 23:52 f2_s -> f2
[root@stone ~]# stat f2
  File: ‘f2’
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 33575038    Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2023-06-22 23:52:28.694172269 +0800
Modify: 2023-06-22 23:52:28.694172269 +0800
Change: 2023-06-22 23:52:28.694172269 +0800
 Birth: -
[root@stone ~]# stat f2_s
  File: ‘f2_s’ -> ‘f2’
  Size: 2               Blocks: 0          IO Block: 4096   symbolic link
Device: fd00h/64768d    Inode: 33575039    Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2023-06-22 23:52:51.119172604 +0800
Modify: 2023-06-22 23:52:51.119172604 +0800
Change: 2023-06-22 23:52:51.119172604 +0800
 Birth: -

可以看到这两个文件的 Inode 不同,Links 都为 1。

使用 unlink 命令删除软连接。

[root@stone ~]# unlink f2_s

find

使用 find 命令查找目录和文件。

常用选项有:

选项含义
-name指定目录或者文件名
-type指定文件类型,可以是 f(文件),d(目录),l(链接)
-size指定文件大小,+ 为大于,- 为小于,单位可以是 c(字节)、w(字数)、b(块数)、k(KB)、M(MB)或 G(GB)
-mtime -mmin指定修改时间,以天或分为单位,+ 为时间之前,- 为时间之内
-maxdepth -mindepth指定最大或最小搜索目录深度
-perm指定权限
-user指定文件所有者
-group指定文件所属组

查找 /var/log 目录下扩展名为 .log 的文件:

[root@stone ~]# find /var/log/ -name *.log
/var/log/tuned/tuned.log
/var/log/audit/audit.log
/var/log/anaconda/anaconda.log
/var/log/anaconda/X.log
/var/log/anaconda/program.log
/var/log/anaconda/packaging.log
/var/log/anaconda/storage.log
/var/log/anaconda/ifcfg.log
/var/log/anaconda/ks-script-l1NlL6.log
/var/log/anaconda/ks-script-yfcGhw.log
/var/log/anaconda/journal.log
/var/log/boot.log
/var/log/yum.log

查找 /var/log 目录下的目录:

[root@stone ~]# find /var/log/ -type d
/var/log/
/var/log/tuned
/var/log/audit
/var/log/anaconda
/var/log/rhsm

查找 /var/log 目录下大于 1 MB 的文件:

[root@stone ~]# find /var/log/ -size +1M
/var/log/anaconda/journal.log

查找 /var/log 目录下在 60 分钟内修改过的文件:

[root@stone ~]# find /var/log -mmin -60
/var/log/audit/audit.log
/var/log/messages
/var/log/cron

查找 /tmp 目录下权限为 700 的文件:

[root@stone ~]# find /tmp/ -perm 700
/tmp/ks-script-i3ZLR4

还可以使用 -exec 选项对查找出来的文件执行指定的命令:

[root@stone ~]# find /var/log -mmin -60 -exec ls -l {} \;
-rw-------. 1 root root 204134 Jun 23 15:20 /var/log/audit/audit.log
-rw-------. 1 root root 348712 Jun 23 15:20 /var/log/messages
-rw-------. 1 root root 4212 Jun 23 15:01 /var/log/cron

其中,{} 表示查找结果,\; 表示命令结束。

rename

使用 rename 批量重命名文件。

语法:

rename [options] expression replacement file...
[root@stone ~]# touch f00.txt f01.txt f02.txt
[root@stone ~]# rename .txt .txt.bak f0*.txt
[root@stone ~]# ls *.txt.bak
f00.txt.bak  f01.txt.bak  f02.txt.bak

编辑和查看文件

在 Linux 操作系统上,很少去创建编辑类似 Word,Excel 这类文档,大部分处理的都是纯文本文件。本节主要介绍如何创建,编辑和查看文件。

vim

使用 vi 或者 vim 来创建和编辑文本。在所有的 Linux 发行版本都有提供 vi 这个文本编辑器,vimvi 的增强版本。这里使用 vim 来演示如何创建和编辑文本。

vim 有三种模式:

  • 一般模式:输入 vim 命令后进入的就是一般模式,编辑模式和命令模式下按 Esc 键进入一般模式。
  • 编辑模式:在一般模式下按 iIoOaArRsScC 键进入编辑模式,可在此模式键入文字。
  • 命令模式:在一般模式下按 :/? 键进入命令模式,可在此模式键入命令。

vi/vim键位图打印版英文

在一般模式下,可以对文本进行移动光标,选择,复制,粘帖,删除等操作。

动作按键
移动光标 1 个字符 或者 kjhl 或者空格;前面可加数字表示移动多个字符
移动光标 1 页PgUpPgDn 或者 Ctrl + fCtrl + b
移动光标半页Ctrl + dCtrl + u
移动到行首Home0(数字 0)
移动到行尾End$
移动到当前屏幕最上方第 1 个字符H(High)
移动到当前屏幕最下方第 1 个字符L(Low)
移动到当前屏幕中间行第 1 个字符M(Middle)
移动到文本最后 1 行G 或者 }}
移动到文本第 1 行gg 或者 {{
移动到文本的第 n 行nG(n 为数字)
向下移动 n 行n + Enter(n 为数字)
向右移动 n 列n + Space(n 为数字)
选择字符或行v 或者 V
选择块Ctrl + v
选择全部文本ggVG
复制一行或多行yy 或者 nyy(n 为数字)
复制该行到首行或到尾行的行ygg 或者 yG
复制光标到行首或行尾的字符y0 或者 y$
粘帖到当前行下面或上面p 或者 P
向后或向前删除 1 个字符x 或者 X
向后或向前删除 n 个字符nx 或者 nX(n 为数字)
删除 1 行或者 n 行dd 或者 ndd(n 为数字)
删除该行到首行或到尾行的行dgg 或者 dG
删除光标到行首或行尾的字符d0 (光标所在字符保留)或者 d$(光标所在字符不保留)
撤销u
重做Ctrl + r
重复前一个动作.

在一般模式下,切换到编辑模式的动作与按键:

动作按键
在当前字符前面或者在当前行第 1 个非空白字符前插入i 或者 I
在当前字符后面或者在当前行最后面插入a 或者 A
在当前行下面或者上面插入o 或者 O

在一般模式下,切换到命令模式的动作与按键:

动作按键
搜索/str:向下搜索字符串 str,使用 n 或者 N 继续向下或者向上搜索
?str:向上搜索字符串 str,使用 n 或者 N 继续向上或者向下搜索
替换:n1,n2s/str1/str2/g:表示将 n1 到 n2 行之间的 str1 替换为 str2
:1,$s/str1/str2/g:表示将文件中所有的 str1 替换为 str2
:1,$s/str1/str2/gc:替换前需要确认
读入:r filename:读取文件添加到当前光标行下
执行:! command:执行操作系统命令
设置:set nu:设置行号
:set hlsearch:设置高亮搜索结果
保存:w:保存
:w filename:另存为
:n1,n2 w filename:将 n1 行到 n2 行之间内容另存为
退出:q:没有修改,直接退出
:q!:放弃修改,强制退出
:wq:保存修改再退出

cat

使用 cat 命令查看文件内容。

查看系统版本:

[root@stone ~]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)

查看内核版本:

[root@stone ~]# cat /proc/version 
Linux version 3.10.0-1127.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Tue Mar 31 23:36:51 UTC 2020

使用 -n 选项为输入增加行号:

[root@stone ~]# cat -n .bash_profile 
     1  # .bash_profile
     2
     3  # Get the aliases and functions
     4  if [ -f ~/.bashrc ]; then
     5          . ~/.bashrc
     6  fi
     7
     8  # User specific environment and startup programs
     9
    10  PATH=$PATH:$HOME/bin
    11
    12  export PATH

more

使用 cat 命令会将文件内容全部输出,如果文件内容太长,则有可能看不到前面的内容,可以使用 more 命令来分页查看。

[root@stone ~]# more .bashrc 
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

more 命令中可以使用的按键有:

按键含义
space(空格键)向下翻页
b向上翻页
Enter(回车键)向下翻一行
/str向下搜索 str,再按 n 重复向下搜索
:f显示文件名及当前行号
q退出

less

除了使用 more,还可以使用功能更多的 less 命令来分页查看文件。

[root@stone ~]# less /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd

[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid

#
# include all files from the config directory
#
!includedir /etc/my.cnf.d

less 命令中可以使用的按键有:

按键含义
space(空格键),PgDn(下页)向下翻页
bPgUp(上页)向上翻页
Enter(回车键)向下翻一行
gG移动到文件的首页或者尾页
/str向下搜索 str,再按 n 或者 N 重复向下或向上搜索
?str向上搜索 str,再按 n 或者 N 重复向上或向下搜索
:f显示文件名及当前页行号
q退出

使用 head 命令查看文件前面指定行的内容,默认为 10 行。

[root@stone ~]# head /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

使用 -n 选项指定行数:

[root@stone ~]# head -n 2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@stone ~]# head -2 /etc/passwd  
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

如果指定的行数为负数,则不显示文件最后面的这些行:

[root@stone ~]# head -n -15 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

如果要一次查看多个文件,可以使用 -q 选项指定不显示文件名:

[root@stone ~]# head -2 /etc/passwd /etc/group
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

==> /etc/group <==
root:x:0:
bin:x:1:
[root@stone ~]# head -2 -q /etc/passwd /etc/group   
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
root:x:0:
bin:x:1:

tail

使用 tail 命令查看文件后面指定行的内容,默认为 10 行。

[root@stone ~]# tail /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

使用 -n 选项指定行数:

[root@stone ~]# tail -n 2 /etc/passwd
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@stone ~]# tail -2 /etc/passwd
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

如果指定的行数为正数,则不显示文件最前面的这些行:

[root@stone ~]# tail -n +15 /etc/passwd
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

使用 -f 选项保持文件处于打开状态,不断显示新添加的行,经常用于查看日志的实时变化:

[root@stone ~]# tail -5f /var/log/messages 
Jun 23 17:54:34 stone dhclient[4059]: bound to 192.168.92.128 -- renewal in 713 seconds.
Jun 23 17:54:34 stone dbus[644]: [system] Successfully activated service 'org.freedesktop.nm_dispatcher'
Jun 23 17:54:34 stone systemd: Started Network Manager Script Dispatcher Service.
Jun 23 17:54:34 stone nm-dispatcher: req:1 'dhcp4-change' [ens33]: new request (2 scripts)
Jun 23 17:54:34 stone nm-dispatcher: req:1 'dhcp4-change' [ens33]: start running ordered scripts...

nl

使用 nlnumber lines)命令查看文件内容,并加上行号。

常用选项有:

  • -b:指定标记行号的方式,包括:
    • a:为所有行标记行号
    • t:为非空行标记行号
  • -n:指定格式,包括:
    • ln:行号在内容左边
    • rn:行号在内容右边
  • -w:行号占用的位数,默认为 6 位
[root@stone ~]# nl -b a .bash_profile
     1  # .bash_profile
     2
     3  # Get the aliases and functions
     4  if [ -f ~/.bashrc ]; then
     5          . ~/.bashrc
     6  fi
     7
     8  # User specific environment and startup programs
     9
    10  PATH=$PATH:$HOME/bin
    11
    12  export PATH

wc

使用 wc 命令统计文件词数和行数。

[root@stone ~]# wc .bash_profile 
 12  27 176 .bash_profile

其中,12 为行数,27 为词数,176 为字节数。

使用 -l 选项只统计行数:

[root@stone ~]# wc -l .bash_profile 
12 .bash_profile

cut

使用 cut 命令对文件内容进行列分割,不影响原文件。默认使用 Tab 进行分割,使用 -d 选项指定分隔符,使用 -f 选项指定需要显示的列。

[root@stone ~]# cut -d ' ' -f 1,4 /etc/redhat-release 
CentOS 7.9.2009

sort

使用 sort 命令对文件内容进行排序,不影响原文件。

常用选项有:

  • -f:忽略大小写
  • -n:按照数字大小排序
  • -r:反向排序
  • -u:去除重复值
  • -t:指定分隔符,默认使用 Tab 进行分割
  • -k:指定排序列
  • -o:输出到文件
[root@stone ~]# sort -t ':' -k 3 -n /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin

uniq

使用 uniq 命令对文件内容进行去重,不影响原文件。

常用选项有:

  • -c:显示该行重复出现的次数
  • -d:只输出重复行
  • -u:只输出不重复行
  • -i:忽略大小写
  • -s N:忽略前面 N 个字符

创建一个文件然后去重:

[root@stone ~]# vim uniq.txt
1
2
2
3
3
3
4

[root@stone ~]# uniq -c -d uniq.txt 
      2 2
      3 3
      
[root@stone ~]# uniq -c -u uniq.txt 
      1 1
      1 4
      
[root@stone ~]# uniq -c uniq.txt 
      1 1
      2 2
      3 3
      1 4      

压缩与打包

在 Linux 上有很多压缩工具,这里只介绍常用的几种。

zip

使用 zip 命令压缩目录和文件,压缩文件以 .zip 为文件后缀名。

常用选项有:

  • -r:压缩目录。
  • -q:静默操作,不显示压缩过程。
  • -d:从压缩文件内删除指定的文件。
  • -f:更新现有文件。
  • -u:更新指定文件,如果压缩文件中没有此文件,则增加到压缩文件。
  • -j:不包含目录。

使用 unzip 命令解压 .zip 文件。

常用选项有:

  • -l:列出压缩文件中的内容。
  • -v:列出压缩文件中的内容,更详细信息。
  • -d:解压到指定目录。
  • -o:覆盖现有文件而不提示。

压缩当前目录下所有以 f 开头的文件:

[root@stone ~]# zip f.zip f*
  adding: f1 (stored 0%)
  adding: f1_h (stored 0%)
  adding: f2 (stored 0%)
  adding: f2_s (stored 0%)
  adding: f3.txt (stored 0%)
  adding: f4 (deflated 52%)
[root@stone ~]# ll f.zip 
-rw-r--r--. 1 root root 939 Jul  2 12:44 f.zip
[root@stone ~]# unzip -l f.zip 
Archive:  f.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  06-22-2023 22:14   f1
        0  06-22-2023 22:14   f1_h
        0  06-22-2023 23:52   f2
        0  06-22-2023 23:52   f2_s
       13  06-23-2023 16:41   f3.txt
      200  06-23-2023 13:45   f4
---------                     -------
      213                     6 files
[root@stone ~]# unzip -v f.zip 
Archive:  f.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 06-22-2023 22:14 00000000  f1
       0  Stored        0   0% 06-22-2023 22:14 00000000  f1_h
       0  Stored        0   0% 06-22-2023 23:52 00000000  f2
       0  Stored        0   0% 06-22-2023 23:52 00000000  f2_s
      13  Stored       13   0% 06-23-2023 16:41 011de4af  f3.txt
     200  Defl:N       96  52% 06-23-2023 13:45 0c43bcd0  f4
--------          -------  ---                            -------
     213              109  49%                            6 files

从压缩文件中删除文件:

[root@stone ~]# zip -d f.zip f4
deleting: f4
[root@stone ~]# unzip -v f.zip 
Archive:  f.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 06-22-2023 22:14 00000000  f1
       0  Stored        0   0% 06-22-2023 22:14 00000000  f1_h
       0  Stored        0   0% 06-22-2023 23:52 00000000  f2
       0  Stored        0   0% 06-22-2023 23:52 00000000  f2_s
      13  Stored       13   0% 06-23-2023 16:41 011de4af  f3.txt
--------          -------  ---                            -------
      13               13   0%                            5 files

静默压缩目录:

[root@stone ~]# zip -r -q d1.zip d1/
[root@stone ~]# ll d1.zip 
-rw-r--r--. 1 root root 294 Jul  2 11:44 d1.zip
[root@stone ~]# unzip -l d1.zip 
Archive:  d1.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  06-22-2023 22:21   d1/
        0  06-22-2023 22:21   d1/f1
---------                     -------
        0                     2 files

修改文件后,更新压缩文件:

[root@stone ~]# echo "Hello Stone" > d1/f1
[root@stone ~]# zip -f d1.zip 
freshening: d1/ (stored 0%)
freshening: d1/f1 (stored 0%)
[root@stone ~]# unzip -l d1.zip
Archive:  d1.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  07-02-2023 12:47   d1/
       12  07-02-2023 12:47   d1/f1
---------                     -------
       12                     2 files

增加文件后,更新压缩文件:

[root@stone ~]# touch d1/f2
[root@stone ~]# echo "Hello CentOS" > d1/f2
[root@stone ~]# zip -u d1.zip d1/f2
  adding: d1/f2 (stored 0%)
[root@stone ~]# unzip -l d1.zip
Archive:  d1.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  07-02-2023 12:50   d1/
       12  07-02-2023 12:47   d1/f1
       13  07-02-2023 12:51   d1/f2
---------                     -------
       25                     3 files

解压到指定目录:

[root@stone ~]# unzip d1.zip -d /tmp/
Archive:  d1.zip
   creating: /tmp/d1/
 extracting: /tmp/d1/f1              
 extracting: /tmp/d1/f2              
 extracting: /tmp/d1/f3

再次解压,覆盖现有文件而不提示:

[root@stone ~]# unzip -o d1.zip -d /tmp/
Archive:  d1.zip
 extracting: /tmp/d1/f1              
 extracting: /tmp/d1/f2              
 extracting: /tmp/d1/f3

如果要解压多个 zip 文件,直接使用 *.zip 会报错:

[root@stone ~]# unzip *.zip -d /tmp/
Archive:  d1.zip
caution: filename not matched:  f.zip

可以使用 \*.zip'*.zip' 或者 "*.zip"

[root@stone ~]# unzip \*.zip -d /tmp/
[root@stone ~]# unzip '*.zip' -d /tmp/
[root@stone ~]# unzip "*.zip" -d /tmp/ 

gzip

使用 gzip 命令压缩文件,压缩文件以 .gz 为文件后缀名。

常用选项有:

  • -c:将压缩文件输出到标准输出中,并保留源文件。
  • -r:递归压缩指定目录以及子目录下的所有文件。
  • -l:列出压缩文件内容。
  • -d:解压缩。

默认情况下,gzip 压缩文件后,源文件就消失了。

[root@stone ~]# ls uniq.*
uniq.txt
[root@stone ~]# gzip uniq.txt 
[root@stone ~]# ls uniq.*     
uniq.txt.gz

使用 -c 选项及重定向,可以保留源文件。

[root@stone ~]# gzip -c f1 > f1.gz
[root@stone ~]# ls f1*
f1  f1.gz

gzip 不能压缩目录,使用 -r 选项也只是压缩目录里面的文件。

[root@stone ~]# ls d1
f1  f2  f3
[root@stone ~]# gzip -r d1/
[root@stone ~]# ls d1
f1.gz  f2.gz  f3.gz

使用 -l 选项查看压缩文件内容。

[root@stone ~]# gzip -l uniq.txt.gz 
         compressed        uncompressed  ratio uncompressed_name
                 38                  14  21.4% uniq.txt

使用 -d 选项解压缩。

[root@stone ~]# gzip -d uniq.txt.gz 
[root@stone ~]# ls uniq.*
uniq.txt
[root@stone ~]# gunzip -d -r d1/
[root@stone ~]# ls d1/
f1  f2  f3

可以使用 zcat 命令查看压缩文件里面的内容而无需解压。

[root@stone ~]# gzip uniq.txt 
[root@stone ~]# zcat uniq.txt.gz 
1
2
2
3
3
3
4

如果文件内容很多,还可以使用 zmore 或者 zless 翻页查看,zgrep 搜索内容。

tar

使用 tar 命令打包多个目录和文件,再使用 gzip 进行压缩。

常用选项有:

  • -c:创建打包文件。

  • -t:列出打包文件内容。

  • -x:还原打包文件中。

  • -v:显示处理过程。

  • -z:使用 gzip 处理打包文件。

  • -f:指定打包文件名。

  • -C:指定还原目录。

打包并压缩目录,然后查看打包文件里面的内容。

[root@stone ~]# tar -cvzf d1.tar.gz d1
d1/
d1/f1
d1/f2
d1/f3

查看打包文件。

[root@stone ~]# tar -tvzf d1.tar.gz 
drwxr-xr-x root/root         0 2023-07-02 21:04 d1/
-rw-r--r-- root/root        12 2023-07-02 12:47 d1/f1
-rw-r--r-- root/root        13 2023-07-02 12:51 d1/f2
-rw-r--r-- root/root         0 2023-07-02 12:58 d1/f3

还原打包文件到指定目录。

[root@stone ~]# tar -xvzf d1.tar.gz -C /tmp/
d1/
d1/f1
d1/f2
d1/f3

Bash

前面在使用 ls -a 命令查看 /root 目录下的文件时,发现有一些包含 bash 的文件,本节就介绍什么是 Bash。

简介

Linux 操作系统的核心称为内核open in new window,用于与计算机硬件交互。作为用户,无法直接操作内核,需要使用称为 Shell 的程序与内核进行交互。Shell 有很多种,比如 Bourne Again shell(bash),C Shell(csh),K Shell(ksh),Z Shell(zsh) 等,CentOS 使用 Bashopen in new window 作为默认 Shell。

使用终端工具连接到 CentOS 进入命令行环境后,就会看到如下 Shell 提示符:

[root@stone ~]# 

其中:

  • root:表示用户名
  • stone:表示主机名
  • ~:表示当前位于用户主目录
  • #:表示用户为 root,如果是其它用户,则为 $

如果默认的 Shell 不是 Bash,可以使用 bash 命令启动:

[root@stone ~]# bash

使用 --version 选项查看 Bash 版本:

[root@stone ~]# bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

使用 exit 命令退出 Bash:

[root@stone ~]# exit

echo

使用 echo 命令在命令行输出文本,变量值或者命令的执行结果。

常用选项有:

  • -e:启用反斜线转义符

常用转义字符有:

  • \\:backslash
  • \a:alert (BEL)
  • \b:backspace
  • \c:produce no further output
  • \e:escape
  • \f:form feed
  • \n:new line
  • \r:carriage return
  • \t:horizontal tab
  • \v:vertical tab
  • \0NNN:byte with octal value NNN (1 to 3 digits)
  • \xHH:byte with hexadecimal value HH (1 to 2 digits)
[root@stone ~]# echo Hello,CentOS
Hello,CentOS
[root@stone ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@stone ~]# echo `date`
Tue Jun 27 22:27:18 CST 2023
[root@stone ~]# echo -e "Hello Linux\nHello World"
Hello Linux
Hello World

快捷键

Bash 常用快捷键如下(不区分大小写):

  • Ctrl + A:移到行首。
  • Ctrl + E:移到行尾。
  • Ctrl + L:清除屏幕并将当前行移到页面顶部。
  • Ctrl + C:中止当前正在执行的命令。
  • Ctrl + Z:将执行的命令放入 Shell 后台并暂停。
  • Shift + PageUp:向上滚动。
  • Shift + PageDown:向下滚动。
  • Ctrl + U:从光标位置删除到行首。
  • Ctrl + K:从光标位置删除到行尾。
  • Ctrl + W:删除光标位置前一个单词。
  • Ctrl + D:关闭 Shell 会话。
  • :浏览已执行命令的历史记录。
  • Tab:自动补全命令和路径。
  • Esc + .:插入上一个命令的最后一个词。
  • Ctrl + R:键入命令的部分字符,自动在历史文件中查询并显示最近一条匹配的结果,按下回车执行。

符号

Bash 中有很多具有特定含义的符号。

使用;(分号)表示命令结束,这样就可以在一行上放置多个命令。

[root@stone ~]# cd /root;ls

无论前一个命令是否执行成功,后面的命令都会执行。

&&

对于 Command1 && Command2,如果 Command1 命令执行成功,才会执行 Command2

[root@stone ~]# ls f3.txt && cat f3.txt 
f3.txt
Hello,CentOS

上面例子中,只有 ls f3.txt 命令执行成功,才会执行 cat f3.txt

[root@stone ~]# ls f4.txt && cat f3.txt 
ls: cannot access f4.txt: No such file or directory

上面例子中,由于 ls f4.txt 命令执行失败,故不会执行 cat f3.txt

||

对于 Command1 || Command2,即使 Command1 命令执行失败,也会执行 Command2

[root@stone ~]# ls f4.txt || cat f3.txt   
ls: cannot access f4.txt: No such file or directory
Hello,CentOS

上面例子中,ls f4.txt 命令执行失败了,但也会执行 cat f3.txt

~

使用 ~(波浪线)表示当前用户的主目录。

[root@stone ~]# ls -d ~
/root

?

使用 ?(问号)匹配文件路径中单个字符。不能匹配路径分隔符(/)。

[root@stone ~]# ls d?/f1
d1/f1
[root@stone ~]# ls d1/f?
d1/f1
[root@stone ~]# ls f?
f1  f2  f4
[root@stone ~]# ls f???
f1_h  f2_s

*

使用 *(星号)匹配文件路径中任意个字符。不能匹配路径分隔符(/)。

[root@stone ~]# ls f*
f1  f1_h  f2  f2_s  f3.txt  f4
[root@stone ~]# ls *.txt
f3.txt  uniq.txt

[]

使用 [](方括号)匹配方括号中所有字符。

[root@stone ~]# ls f[12]
f1  f2

[] 最前面使用 ^ 或者 ! 表示反向匹配。

[root@stone ~]# ls [!adu]*
f1  f1_h  f2  f2_s  f3.txt  f4

[] 最里面使用 - 表示连续的范围。

[root@stone ~]# ls f[1-5]
f1  f2  f4
[root@stone ~]# ls f[!2-9]*
f1  f1_h

{}

使用 {}(大括号)匹配大括号中的所有值,以逗号分隔。

[root@stone ~]# ls {f3,uniq}.txt
f3.txt  uniq.txt

{} 里面使用 .. 表示连续的范围。

[root@stone ~]# ls f{1..4}
ls: cannot access f3: No such file or directory
f1  f2  f4

$

使用 $ 引用变量。

[root@stone ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

变量除了可以放在 $ 后面,还可以放在 ${} 里面。

[root@stone ~]# echo ${USER}
root

当前 Shell 的 PID:

[root@stone ~]# echo $$
7706

$()

使用 $() 获取命令结果。

[root@stone ~]# echo $(date)
Wed Jun 28 21:09:06 CST 2023

也可以将命令放在反引号中。

[root@stone ~]# echo `date`
Wed Jun 28 21:23:25 CST 2023

$(())

使用 $(()) 获取整数运算结果。

[root@stone ~]# echo $((60*60*24*7))
604800

\

使用 \(反斜杠)转义特殊字符。

[root@stone ~]# echo \$PATH
$PATH

当按下 Enter 键,表示命令结束,开始执行。如果命令太长,需要换行显示,此时可以使用 \Enter 进行转义,使其变成一个普通字符,Bash 会将其当作长度为 0 的空字符处理,从而可以将一行命令写成多行。

[root@stone ~]# ls /root/f1 /root/f2* \
> /root/f3*
/root/f1  /root/f2  /root/f2_s  /root/f3.txt

'

使用 '(单引号)显示字符,各种特殊字符在单引号里面,都会变为普通字符。

[root@stone ~]# echo '$PATH'
$PATH
[root@stone ~]# echo '$((60*60*24*7))'
$((60*60*24*7))

"

使用 "(双引号)显示字符,与单引号类似,但对于 $`\,仍保留特殊含义。

[root@stone ~]# echo "$PATH"
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@stone ~]# echo "`date`"
Wed Jun 28 21:45:38 CST 2023

重定向

Linux 重定向是一种将命令的输入或输出从默认位置更改为另一个位置的方法。可以使用重定向符号将命令的输出发送到文件中,或者将文件中的内容作为命令的输入。例如,使用 > 符号可以将命令的输出重定向到一个文件中,而使用 < 符号可以将文件中的内容作为命令的输入。

在 Linux 中,每个进程都有三个标准流:标准输入(stdin)、标准输出(stdout)和标准错误(stderr)。

  • 标准输入(stdin)是进程从用户读取输入数据的流,对应的文件描述符位 0。默认情况下,stdin 连接到键盘(即用户输入)。

  • 标准输出(stdout)是进程输出数据的流,对应的文件描述符位 1。默认情况下,stdout 连接到终端(即屏幕)。

  • 标准错误(stderr)是进程输出错误信息的流,对应的文件描述符位 2。默认情况下,stderr 连接到终端(即屏幕)。

图片

可以使用重定向符号将这些流重定向到其他位置,例如将 stdout 重定向到文件中。

输出重定向

使用 >(覆盖)或者 >>(追加)对输出进行重定向。

image-20230701120156907

[root@stone ~]# ls > ls.txt
[root@stone ~]# cat ls.txt
anaconda-ks.cfg
d1
f1
f1_h
f2
f2_s
f3.txt
f4
ls.txt
uniq.txt
[root@stone ~]# ls f1 > ls.txt
[root@stone ~]# cat ls.txt
f1
[root@stone ~]# ls f2 >> ls.txt 
[root@stone ~]# cat ls.txt
f1
f2

以上是对标准输出(stdout)的重定向,还可以对标准错误(stderr)重定向。

[root@stone ~]# ls f5 2>lserr.txt  
[root@stone ~]# cat lserr.txt
ls: cannot access f5: No such file or directory
[root@stone ~]# ls f6 2>>lserr.txt 
[root@stone ~]# cat lserr.txt
ls: cannot access f5: No such file or directory
ls: cannot access f6: No such file or directory

同时对标准输出(stdout)和标准错误(stderr)重定向。

[root@stone ~]# ls f1 f6 > ls.txt 2>lserr.txt 
[root@stone ~]# cat ls.txt 
f1
[root@stone ~]# cat lserr.txt 
ls: cannot access f6: No such file or directory

还可以使用 2>&1 将标准输出(stdout)和标准错误(stderr)重定向到一个文件。

[root@stone ~]# ls f1 f6 > ls.txt 2>&1
[root@stone ~]# cat ls.txt 
ls: cannot access f6: No such file or directory
f1

如果不想看到错误,也不想存储错误,可以将标准错误(stderr)重定向到黑洞设备 /dev/null

[root@stone ~]# ls f1 f6 2>/dev/null
f1

输入重定向

使用 < 以文件代替键盘作为标准输入。输入重定向并不常用,因为大多数 Linux 命令都可以接受文件名作为参数。

image-20230701120926811

例如将文件 f3.txt 的内容作为标准输入,重定向给 cat 命令并输出到文件 f5.txt

[root@stone ~]# cat > f5.txt < f3.txt 
[root@stone ~]# cat f5.txt 
Hello,CentOS

上面的命令其实可以直接使用 cat 命令读取文件 f3.txt 再输出重定向给文件 f5.txt

[root@stone ~]# cat f3.txt > f5.txt 
[root@stone ~]# cat f5.txt 
Hello,CentOS

使用 <<(称为 Here Document)指定标准输入的开始标记(一般为 EOF),完成后再输入此标记作为结束符。可以在屏幕输入字符串重定向给某个命令。

[root@stone ~]# cat > f6.txt << EOF
> Hello World,
> Hello Centos.
> EOF
[root@stone ~]# cat f6.txt 
Hello World,
Hello Centos.

管道

前面使用输出重定向可以将命令的执行结果重定向到文件中,还可以使用管道符(|)将上一个命令的标准输出作为下一个命令的标准输入,类似于数据在管道中流动,这样就可以使用多个命令对数据进行处理。

image-20230701120117706

例如统计当前目录下有多少目录和文件,就可以将 ls 命令的标准输出通过管道符(|)传递给 wc 命令作为其标准输入,即可得出计算结果。

[root@stone ~]# ls | wc -l
13

能够接收标准输入的命令就称为管道命令,除了前面的 morelessheadtailwccutsortuniq 外,常用的管道命令还有 trteesplitxargs 等。

tr

使用 tr 命令对输入内容进行替换或删除。

常用选项有:

  • -d:删除指定字符串。
  • -s:去除重复字符串。

将小写字符替换为大写字符:

[root@stone ~]# hostname | tr '[a-z]' '[A-Z]'
STONE

: 替换为回车:

[root@stone ~]# echo $PATH | tr ':' '\n'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin

使用 -d 选项去掉文件后缀名:

[root@stone ~]# ls *.txt | tr -d '.txt'
f3
f5
f6
lserr
ls
uniq

使用 -s 选项去掉文件中多余的空行:

[root@stone ~]# cat .bash_profile | tr -s ['\n']
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH

tee

使用 tee 命令可以将标准输入分别输出到屏幕(标准输出)和文件中。

常用选项有:

  • -a:将标准输入追加到文件中。

image-20230701193120921

查看文件的同时将结果保存到文件 output.txt 中。

[root@stone ~]# ls f2* | tee output.txt
f2
f2_s
[root@stone ~]# cat output.txt 
f2
f2_s

使用 -a 选项将结果追加到文件中。

[root@stone ~]# ls f2* | tee -a output.txt
f2
f2_s
[root@stone ~]# cat output.txt
f2
f2_s
f2
f2_s

split

使用 split 命令将一个文件分隔成多个小文件。

常用选项有:

  • -b:指定每个小文件的大小。
  • -l:指定每个小文件的行数。

300k 大小分隔 /etc/services,指定文件前缀为 services,如果不指定,默认为 x

[root@stone ~]# split -b 300k /etc/services services
[root@stone ~]# ll -h servicesa*  
-rw-r--r--. 1 root root 300K Jul  1 19:55 servicesaa
-rw-r--r--. 1 root root 300K Jul  1 19:55 servicesab
-rw-r--r--. 1 root root  55K Jul  1 19:55 servicesac

1000 行分隔 /var/log/messages,指定文件前缀为 messages

[root@stone ~]# split -l 1000 /var/log/messages messages
[root@stone ~]# ll messagesa*
-rw-r--r--. 1 root root 82122 Jul  1 20:00 messagesaa
-rw-r--r--. 1 root root 85536 Jul  1 20:00 messagesab
-rw-r--r--. 1 root root 83392 Jul  1 20:00 messagesac
-rw-r--r--. 1 root root 32748 Jul  1 20:00 messagesad

xargs

使用 xargs 命令从标准输入中读取数据,然后传递给不能从标准输入中读取数据的命令,作为其参数,默认使用空格作为分隔符。

常用选项有:

  • -d:指定分隔符。
  • -n:指定一次处理的参数个数。
  • -p:需要用户进行确认。
  • -0:使用 null 作为分隔符,用于处理包含空格的文件名,一般与 find 命令及其 -print0 选项一起使用。
  • -t:执行前先输出命令
  • -I:替换
[root@stone ~]# find /root/ -name f3.txt | xargs ls -l            
-rw-r--r--. 1 root root 13 Jun 23 16:41 /root/f3.txt
[root@stone ~]# find . -type f -name "messages*" -print0 | xargs -0 rm -f
[root@stone ~]# find . -type f -name "services*" -print0 | xargs -0 -p rm -f        
rm -f ./servicesaa ./servicesab ./servicesac ?...y

为目录下所有指定文件增加一个后缀名:

[root@stone ~]# ls *.txt | xargs -t -I{} mv {} {}.bak

-

使用 - 符号来代替标准输出和标准输入,以替换命令中所需要的文件名。

[root@stone ~]# tar -cvf - d1 | tar -xvf - -C /tmp/
d1/
d1/f1
d1/f2
d1/f3
d1/
d1/f1
d1/f2
d1/f3

环境变量

与 Windows 类似,Linux 的每个用户都有环境变量。

env

使用 env 命令查看当前的环境变量。

[root@stone ~]# env
XDG_SESSION_ID=2
HOSTNAME=stone
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.92.1 61705 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root
LANG=en_US.UTF-8
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
LOGNAME=root
SSH_CONNECTION=192.168.92.1 61705 192.168.92.128 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env

其中:

  • PATH:指定了命令的搜索路径,以 : 分隔。 可以使用 which 命令查看相关命令的路径。
[root@stone ~]# which env
/usr/bin/env
[root@stone ~]# which ls
alias ls='ls --color=auto'
        /usr/bin/ls

set

使用 set 命令查看当前的 Shell 变量。

[root@stone ~]# set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(2)-release'
COLUMNS=104
DIRSTACK=()
EUID=0
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/root
HOSTNAME=stone
HOSTTYPE=x86_64
ID=0
IFS=$' \t\n'
LANG=en_US.UTF-8
LESSOPEN='||/usr/bin/lesspipe.sh %s'
LINES=37
LOGNAME=root
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:'
MACHTYPE=x86_64-redhat-linux-gnu
MAIL=/var/spool/mail/root
MAILCHECK=60
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PIPESTATUS=([0]="2")
PPID=1487
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
PS1='[\u@\h \W]\$ '
PS2='> '
PS4='+ '
PWD=/root
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
SELINUX_USE_CURRENT_RANGE=
SHELL=/bin/bash
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
SHLVL=1
SSH_CLIENT='192.168.92.1 63109 22'
SSH_CONNECTION='192.168.92.1 63109 192.168.92.128 22'
SSH_TTY=/dev/pts/1
TERM=xterm
UID=0
USER=root
XDG_RUNTIME_DIR=/run/user/0
XDG_SESSION_ID=2
_=-help
colors=/root/.dircolors

其中:

  • PS1:指定命令提示符
    • \u 表示用户名
    • \h 表示主机名
    • \W 表示最后的目录名,主目录为 ~
    • \$ 表示提示字符,如果是 root 用户,提示符为 # ,普通用户则为 $

export

使用 export 命令创建环境变量,在当前 Shell 环境及其子程序中有效。

[root@stone ~]# export ORACLE_SID=stone
[root@stone ~]# echo $ORACLE_SID
stone
[root@stone ~]# bash
[root@stone ~]# echo $ORACLE_SID
stone

如果不使用 export 命令创建环境变量,则只在当前 Shell 环境有效。

[root@stone ~]# MYNAME=stone
[root@stone ~]# echo $MYNAME
stone
[root@stone ~]# bash
[root@stone ~]# echo $MYNAME

[root@stone ~]# 

unset

使用 unset 命令清除环境变量。

[root@stone ~]# unset ORACLE_SID
[root@stone ~]# echo $ORACLE_SID

[root@stone ~]# 

环境配置文件

前面使用 export 命令创建的环境变量只在当前 Shell 环境及其子程序中有效,退出当前 Shell 后就消失了,再次登录后需要重新创建。但是我们一登录到 Shell 后,执行 env 命令就可以看到很多环境变量,这是因为这些环境变量是保存在环境配置文件中的,在登录到 Shell 后,就会读取环境配置文件,以便创建这些环境变量。

环境变量文件有:

  • /etc/profile:整个系统的环境配置文件,登录到 Shell 后会读取该文件。

内容如下:

[root@stone ~]# cat /etc/profile
# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}


if [ -x /usr/bin/id ]; then
    if [ -z "$EUID" ]; then
        # ksh workaround
        EUID=`/usr/bin/id -u`
        UID=`/usr/bin/id -ru`
    fi
    USER="`/usr/bin/id -un`"
    LOGNAME=$USER
    MAIL="/var/spool/mail/$USER"
fi

# Path manipulation
if [ "$EUID" = "0" ]; then
    pathmunge /usr/sbin
    pathmunge /usr/local/sbin
else
    pathmunge /usr/local/sbin after
    pathmunge /usr/sbin after
fi

HOSTNAME=`/usr/bin/hostname 2>/dev/null`
HISTSIZE=1000
if [ "$HISTCONTROL" = "ignorespace" ] ; then
    export HISTCONTROL=ignoreboth
else
    export HISTCONTROL=ignoredups
fi

export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL

# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
    umask 002
else
    umask 022
fi

for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then 
            . "$i"
        else
            . "$i" >/dev/null
        fi
    fi
done

unset i
unset -f pathmunge

可以看到 /etc/profile 文件创建了 PATHUSERLOGNAMEMAILHOSTNAMEHISTSIZEHISTCONTROL 这几个环境变量,并读取 /etc/profile.d/*.sh/etc/profile.d/sh.local 文件。

/etc/profile.d/*.sh 包含的文件有:

[root@stone ~]# ll /etc/profile.d/*.sh       
-rw-r--r--. 1 root root  841 Oct 13  2020 /etc/profile.d/256term.sh
-rw-r--r--. 1 root root  201 Mar 25  2017 /etc/profile.d/colorgrep.sh
-rw-r--r--. 1 root root 1606 Aug  6  2019 /etc/profile.d/colorls.sh
-rw-r--r--. 1 root root 2703 Oct 13  2020 /etc/profile.d/lang.sh
-rw-r--r--. 1 root root  121 Jul 31  2015 /etc/profile.d/less.sh
-rw-r--r--. 1 root root  269 Dec 16  2020 /etc/profile.d/vim.sh
-rw-r--r--. 1 root root  169 Jan 28  2014 /etc/profile.d/which2.sh
  • /etc/profile.d/256term.sh:创建 TERMTERMCAP 环境变量。

内容如下:

[root@stone ~]# cat /etc/profile.d/256term.sh
# Enable 256 color capabilities for appropriate terminals

# Set this variable in your local shell config (such as ~/.bashrc)
# if you want remote xterms connecting to this system, to be sent 256 colors.
# This must be set before reading global initialization such as /etc/bashrc.
#   SEND_256_COLORS_TO_REMOTE=1

# Terminals with any of the following set, support 256 colors (and are local)
local256="$COLORTERM$XTERM_VERSION$ROXTERM_ID$KONSOLE_DBUS_SESSION"

if [ -n "$local256" ] || [ -n "$SEND_256_COLORS_TO_REMOTE" ]; then

  case "$TERM" in
    'xterm') TERM=xterm-256color;;
    'screen') TERM=screen-256color;;
    'Eterm') TERM=Eterm-256color;;
  esac
  export TERM

  if [ -n "$TERMCAP" ] && [ "$TERM" = "screen-256color" ]; then
    TERMCAP=$(echo "$TERMCAP" | sed -e 's/Co#8/Co#256/g')
    export TERMCAP
  fi
fi

unset local256
  • /etc/profile.d/colorgrep.sh:创建 grepegrepfgrep 命令别名。

内容如下:

[root@stone ~]# cat /etc/profile.d/colorgrep.sh
# color-grep initialization

/usr/libexec/grepconf.sh -c || return

alias grep='grep --color=auto' 2>/dev/null
alias egrep='egrep --color=auto' 2>/dev/null
alias fgrep='fgrep --color=auto' 2>/dev/null
  • /etc/profile.d/colorls.sh:创建 lll.ls 命令别名。

内容如下:

[root@stone ~]# cat /etc/profile.d/colorls.sh
# color-ls initialization

# Skip all for noninteractive shells.
[ ! -t 0 ] && return

#when USER_LS_COLORS defined do not override user LS_COLORS, but use them.
if [ -z "$USER_LS_COLORS" ]; then

  alias ll='ls -l' 2>/dev/null
  alias l.='ls -d .*' 2>/dev/null

  INCLUDE=
  COLORS=

  for colors in "$HOME/.dir_colors.$TERM" "$HOME/.dircolors.$TERM" \
      "$HOME/.dir_colors" "$HOME/.dircolors"; do
    [ -e "$colors" ] && COLORS="$colors" && \
    INCLUDE="`/usr/bin/cat "$COLORS" | /usr/bin/grep '^INCLUDE' | /usr/bin/cut -d ' ' -f2-`" && \
    break
  done

  [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS.$TERM" ] && \
  COLORS="/etc/DIR_COLORS.$TERM"

  [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS.256color" ] && \
  [ "x`/usr/bin/tty -s && /usr/bin/tput colors 2>/dev/null`" = "x256" ] && \
  COLORS="/etc/DIR_COLORS.256color"

  [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS" ] && \
  COLORS="/etc/DIR_COLORS"

  # Existence of $COLORS already checked above.
  [ -n "$COLORS" ] || return

  if [ -e "$INCLUDE" ];
  then
    TMP="`/usr/bin/mktemp .colorlsXXX -q --tmpdir=/tmp`"
    [ -z "$TMP" ] && return

    /usr/bin/cat "$INCLUDE" >> $TMP
    /usr/bin/grep -v '^INCLUDE' "$COLORS" >> $TMP

    eval "`/usr/bin/dircolors --sh $TMP 2>/dev/null`"
    /usr/bin/rm -f $TMP
  else
    eval "`/usr/bin/dircolors --sh $COLORS 2>/dev/null`"
  fi

  [ -z "$LS_COLORS" ] && return
  /usr/bin/grep -qi "^COLOR.*none" $COLORS >/dev/null 2>/dev/null && return
fi

unset TMP COLORS INCLUDE

alias ll='ls -l --color=auto' 2>/dev/null
alias l.='ls -d .* --color=auto' 2>/dev/null
alias ls='ls --color=auto' 2>/dev/null
  • /etc/profile.d/lang.sh:创建 LANG 环境变量。

内容如下:

[root@stone ~]# cat /etc/profile.d/lang.sh
# /etc/profile.d/lang.sh - set i18n stuff

sourced=0

if [ -n "$LANG" ]; then
    saved_lang="$LANG"
    [ -f "$HOME/.i18n" ] && . "$HOME/.i18n" && sourced=1
    LANG="$saved_lang"
    unset saved_lang
else
    for langfile in /etc/locale.conf "$HOME/.i18n" ; do
        [ -f $langfile ] && . $langfile && sourced=1
    done
fi

if [ "$sourced" = 1 ]; then
    [ -n "$LANG" ] && export LANG || unset LANG
    [ -n "$LC_ADDRESS" ] && export LC_ADDRESS || unset LC_ADDRESS
    [ -n "$LC_CTYPE" ] && export LC_CTYPE || unset LC_CTYPE
    [ -n "$LC_COLLATE" ] && export LC_COLLATE || unset LC_COLLATE
    [ -n "$LC_IDENTIFICATION" ] && export LC_IDENTIFICATION || unset LC_IDENTIFICATION
    [ -n "$LC_MEASUREMENT" ] && export LC_MEASUREMENT || unset LC_MEASUREMENT
    [ -n "$LC_MESSAGES" ] && export LC_MESSAGES || unset LC_MESSAGES
    [ -n "$LC_MONETARY" ] && export LC_MONETARY || unset LC_MONETARY
    [ -n "$LC_NAME" ] && export LC_NAME || unset LC_NAME
    [ -n "$LC_NUMERIC" ] && export LC_NUMERIC || unset LC_NUMERIC
    [ -n "$LC_PAPER" ] && export LC_PAPER || unset LC_PAPER
    [ -n "$LC_TELEPHONE" ] && export LC_TELEPHONE || unset LC_TELEPHONE
    [ -n "$LC_TIME" ] && export LC_TIME || unset LC_TIME
    if [ -n "$LC_ALL" ]; then
       if [ "$LC_ALL" != "$LANG" ]; then
         export LC_ALL
       else
         unset LC_ALL
       fi
    else
       unset LC_ALL
    fi
    [ -n "$LANGUAGE" ] && export LANGUAGE || unset LANGUAGE
    [ -n "$LINGUAS" ] && export LINGUAS || unset LINGUAS
    [ -n "$_XKB_CHARSET" ] && export _XKB_CHARSET || unset _XKB_CHARSET
    
    consoletype=$CONSOLETYPE
    if [ -z "$consoletype" ]; then
      consoletype=$(/sbin/consoletype stdout)
    fi

    if [ -n "$LANG" ]; then
      case $LANG in
        *.utf8*|*.UTF-8*)
        if [ "$TERM" = "linux" ]; then
            if [ "$consoletype" = "vt" ]; then
                case $LANG in 
                        ja*) LANG=en_US.UTF-8 ;;
                        ko*) LANG=en_US.UTF-8 ;;
                        si*) LANG=en_US.UTF-8 ;;
                        zh*) LANG=en_US.UTF-8 ;;
                        ar*) LANG=en_US.UTF-8 ;;
                        fa*) LANG=en_US.UTF-8 ;;
                        he*) LANG=en_US.UTF-8 ;;
                        en_IN*) ;;
                        *_IN*) LANG=en_US.UTF-8 ;;
                esac
            fi
        fi
        ;;
        *)
        if [ "$TERM" = "linux" ]; then
            if [ "$consoletype" = "vt" ]; then
                case $LANG in 
                        ja*) LANG=en_US ;;
                        ko*) LANG=en_US ;;
                        si*) LANG=en_US ;;
                        zh*) LANG=en_US ;;
                        ar*) LANG=en_US ;;
                        fa*) LANG=en_US ;;
                        he*) LANG=en_US ;;
                        en_IN*) ;;
                        *_IN*) LANG=en_US ;;
                esac
            fi
        fi
        ;;
      esac
    fi

    unset SYSFONTACM SYSFONT consoletype
fi
unset sourced
unset langfile

这个文件会调用 /etc/locale.conf 文件,创建了 LANG 变量,指定语言(en),国家(US)及字符集(UTF-8),内容如下:

[root@stone ~]# cat /etc/locale.conf
LANG="en_US.UTF-8"
  • /etc/profile.d/less.sh:创建 LESSOPEN 环境变量,用于指定 less 命令的输入处理器。

内容如下:

[root@stone ~]# cat /etc/profile.d/less.sh
# less initialization script (sh)
[ -x /usr/bin/lesspipe.sh ] && export LESSOPEN="${LESSOPEN-||/usr/bin/lesspipe.sh %s}"
  • /etc/profile.d/vim.sh:创建 vi 命令别名。

内容如下:

[root@stone ~]# cat /etc/profile.d/vim.sh
if [ -n "$BASH_VERSION" -o -n "$KSH_VERSION" -o -n "$ZSH_VERSION" ]; then
  [ -x /usr/bin/id ] || return
  ID=`/usr/bin/id -u`
  [ -n "$ID" -a "$ID" -le 200 ] && return
  # for bash and zsh, only if no alias is already set
  alias vi >/dev/null 2>&1 || alias vi=vim
fi
  • /etc/profile.d/which2.sh:创建 which 命令别名。

内容如下:

[root@stone ~]# cat /etc/profile.d/which2.sh
# Initialization script for bash and sh

# export AFS if you are in AFS environment
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
  • /etc/profile.d/sh.local:可以将自定义的环境变量添加到此文件,作用于所有用户。

内容如下:

[root@stone ~]# cat /etc/profile.d/sh.local
#Add any required envvar overrides to this file, it is sourced from /etc/profile
  • ~/.bash_profile:用户的环境配置文件,只作用于当前用户。

内容如下:

[root@stone ~]# cat ~/.bash_profile 
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH

可以看到会判断是否有 ~/.bashrc 文件,如果有就读取该文件。然后为 PATH 环境变量增加 $HOME/bin 这个目录。可以在此文件中添加特定于当前用户的环境变量。

  • ~/.bashrc:创建 rmcpmv 命令别名。然后判断是否有 /etc/bashrc,如果有就读取该文件。

内容如下:

[root@stone ~]# cat ~/.bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi
  • /etc/bashrc:指定 $PS1umask 以及读取 /etc/profile.d/*.sh
[root@stone ~]# cat /etc/bashrc
# /etc/bashrc

# System wide functions and aliases
# Environment stuff goes in /etc/profile

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

# are we an interactive shell?
if [ "$PS1" ]; then
  if [ -z "$PROMPT_COMMAND" ]; then
    case $TERM in
    xterm*|vte*)
      if [ -e /etc/sysconfig/bash-prompt-xterm ]; then
          PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm
      elif [ "${VTE_VERSION:-0}" -ge 3405 ]; then
          PROMPT_COMMAND="__vte_prompt_command"
      else
          PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
      fi
      ;;
    screen*)
      if [ -e /etc/sysconfig/bash-prompt-screen ]; then
          PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
      else
          PROMPT_COMMAND='printf "\033k%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
      fi
      ;;
    *)
      [ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=/etc/sysconfig/bash-prompt-default
      ;;
    esac
  fi
  # Turn on parallel history
  shopt -s histappend
  history -a
  # Turn on checkwinsize
  shopt -s checkwinsize
  [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
  # You might want to have e.g. tty in prompt (e.g. more virtual machines)
  # and console windows
  # If you want to do so, just add e.g.
  # if [ "$PS1" ]; then
  #   PS1="[\u@\h:\l \W]\\$ "
  # fi
  # to your custom modification shell script in /etc/profile.d/ directory
fi

if ! shopt -q login_shell ; then # We're not a login shell
    # Need to redefine pathmunge, it get's undefined at the end of /etc/profile
    pathmunge () {
        case ":${PATH}:" in
            *:"$1":*)
                ;;
            *)
                if [ "$2" = "after" ] ; then
                    PATH=$PATH:$1
                else
                    PATH=$1:$PATH
                fi
        esac
    }

    # By default, we want umask to get set. This sets it for non-login shell.
    # Current threshold for system reserved uid/gids is 200
    # You could check uidgid reservation validity in
    # /usr/share/doc/setup-*/uidgid file
    if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
       umask 002
    else
       umask 022
    fi

    SHELL=/bin/bash
    # Only display echos from profile.d scripts if we are no login shell
    # and interactive - otherwise just process them to set envvars
    for i in /etc/profile.d/*.sh; do
        if [ -r "$i" ]; then
            if [ "$PS1" ]; then
                . "$i"
            else
                . "$i" >/dev/null
            fi
        fi
    done

    unset i
    unset -f pathmunge
fi
# vim:ts=4:sw=4
  • ~/.bash_logout:指定退出 Shell 时执行的操作。
[root@stone ~]# cat ~/.bash_logout
# ~/.bash_logout

在使用中,可以将 Shell 分为:

  • Login Shell:登录后获取的 Shell,例如使用终端登录或者执行 su - username 命令获取的 Shell,此时会读取 /etc/profile~/.bash_profile 文件。

image-20230708211452292

  • No-Login Shell:无需登录获取的 Shell,例如执行 bash 或者 su username 命令获取的 Shell,此时会读取 ~/.bashrc 文件。

image-20230708211804543

source

使用 source 命令或者 . (点)读取环境配置文件。

如果修改了环境配置文件,比如在 ~/.bash_profile 文件中增加了环境变量,使用 source 命令读取该文件后,即可让增加的环境变量生效。

[root@stone ~]# echo "export DISPLAY=192.168.92.128:0.0" >> ~/.bash_profile       
[root@stone ~]# echo $DISPLAY

[root@stone ~]# source ~/.bash_profile
[root@stone ~]# echo $DISPLAY         
192.168.92.128:0.0

命令别名

可以为带某个选项的命令或者一组命令指定一个别名,方便使用。

alias

使用 alias 命令查看和指定命令别名。

查看当前所有命令别名:

[root@stone ~]# alias 
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

创建命令别名:

[root@stone ~]# alias cls='clear'
[root@stone ~]# alias cls
alias cls='clear'

注意,此时创建的命令别名只在当前会话有效,断开该会话后,该命令别名消失。可以将 alias cls='clear' 加入到 .bashrc 或者 .bash_profile 文件中,永久生效。

unalias

使用 unalias 命令取消命令别名。

[root@stone ~]# unalias cls

如果不想取消命令别名,但有时又需要使用原始命令,则可以使用 \

[root@stone ~]# \rm uniq.txt.gz

此时就不会使用 rm -i 命令,使用 rm 命令直接删除,慎用。

type

使用 type 命令查看命令的类型。

常用选项有:

  • -a:列出指定命令的所有路径,包括别名。
  • -t:列出指定命令的类型,有:
    • file:表示外部命令
    • alias:表示别名
    • builtin:表示 Bash 自带命令
[root@stone ~]# type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls
[root@stone ~]# type -t -a ls
alias
file
[root@stone ~]# type -a echo
echo is a shell builtin
echo is /usr/bin/echo

可以看到 ls 命令有 2 个,那么发出 ls 命令的时候,使用哪一个命令呢。实际上就是按照 type 或者 which 命令的输出顺序来决定的。

命令的选择顺序具体如下:

  1. 以相对/绝对路径执行命令,例如 /usr/bin/ls
  2. 命令的别名。
  3. Bash 自带的命令。
  4. 通过 PATH 环境变量找到的第一个命令。

命令历史记录

命令历史记录的操作过程如下:

  • 登录到 Shell 后,会从 ~/.bash_history 文件中读取命令历史记录到缓冲区。
  • 在操作时,会将执行的命令记录到缓冲区。
  • 在退出 Shell 时,会将缓冲区的命令保存到 ~/.bash_history 文件中。

涉及到的环境变量如下:

  • HISTSIZE:控制缓冲区历史记录的最大个数,默认为 1000,设置为 0 表示禁用历史记录。

  • HISTFILE:指定历史记录文件,默认为 ~/.bash_history

  • HISTFILESIZE:控制历史记录文件中的最大个数,默认为 1000,设置为 0 表示禁用历史记录。

  • HISTIGNORE:设置哪些命令不记录到历史记录。

  • HISTTIMEFORMAT:设置历史记录显示的时间格式,默认不显示时间,可以设置为 export HISTTIMEFORMAT="%F %T " 显示时间戳。

  • HISTCONTROL:扩展的控制选项,可以为:

    • ignorespace:忽略空格开头的命令。
    • ignoredups:忽略连续重复命令,默认值。
    • ignoreboth:表示上述两个参数都设置。

history

除了可以使用方向键 或者 浏览已执行命令的历史记录,还使用 history 命令查看已执行命令的历史记录。

常用选项有:

  • n:数字,表示列出最近的 n 条历史记录。
[root@stone ~]# history 2
    2  ls f1
    3  history 2
  • -c:清除缓冲区所有命令历史记录。
[root@stone ~]# history -c
[root@stone ~]# history 
    1  history 
  • -d:删除某条历史记录。
[root@stone ~]# history 
    1  history 
    2  ls
    3  history 
[root@stone ~]# history -d 2
[root@stone ~]# history 
    1  history 
    2  history 
    3  history -d 2
    4  history
  • -a:将登录到 Shell 后执行的命令写入到 ~/.bash_history 文件中。
[root@stone ~]# history -a
[root@stone ~]# tail -5 ~/.bash_history 
history 
history 
history -d 2
history 
history -a
  • -r:读取 ~/.bash_history 文件内容到缓冲区。
[root@stone ~]# history -r

!

使用 ! (叹号)来快速执行某个历史命令。

  • 使用 ! + 数字 执行某个编号的历史命令。
[root@stone ~]# history 
    1  exit
    2  ls
    3  alias 
    4  history 
[root@stone ~]# !3
alias 
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
  • 使用 !! 执行上一个命令。
[root@stone ~]# !!
  • 使用 ! + 命令开头字符串 执行最近以某个字符串开头的命令。
[root@stone ~]# !al
  • 使用 ! + 命令开头字符串 + :p 列出最近以某个字符串开头的命令,然后使用方向键 选择执行。
[root@stone ~]# !al:p
alias 
[root@stone ~]# alias 
  • 使用 ! + ? + 命令包含字符串 执行最近包含某个字符串的命令。
[root@stone ~]# !?lia

还可以按下 Ctrl + R 后,键入命令的部分字符,自动在历史文件中查询并显示最近一条匹配的结果,按下回车执行。

正则

正则表达式是一种用于匹配和操作字符串的工具,它可以用来检查字符串是否符合特定的模式,或者从字符串中提取满足特定模式的子串。正则表达式通常由一些特殊字符和普通字符组成,这些字符组合在一起形成一个模式,用于描述要匹配的字符串的特征和结构。在编程和文本处理中,正则表达式是一个非常强大和常用的工具。

简而言之,正则表达式就是使用有限的字符,来匹配无限字符。

语法

正则表达式可以分为:

  • 元字符,包括 . ? * + { } ^ $ [ ] - ( ) | \
字符含义
.匹配任意一个字符
?匹配前面的子表达式 0 或者 1 次
*匹配前面的子表达式 0 或者多次
+匹配前面的子表达式 1 或者多次
{n}匹配前面的子表达式 n 次
{n,}匹配前面的子表达式至少 n 次
{n,m}匹配前面的子表达式至少 n 次,至多 m 次
{,m}匹配前面的子表达式至多 m 次
^匹配文本行开头
$匹配文本行结尾
[xyz]匹配 xyz 中的任一字符
[^xyz]匹配 xyz 之外的任一字符
[a-z]匹配 az 的任一字符
[^a-z]匹配 az 之外的任一字符
abc|xyz匹配 abc 或者 xyz
(xyz)匹配 xyz 字符串
(abc|xyz)匹配 abc 或者 xyz
\b匹配一个单词边界,也就是单词和空格间的位置。
\B匹配一个非单词边界
\d匹配一个数字,等价于 [0-9]
\D匹配一个非数字,等价于 [^0-9]
\w匹配一个字母、数字、下划线,等价于 [A-Za-z0-9_]
\W匹配一个非字母、数字、下划线,等价于 [^A-Za-z0-9_]
\<匹配单词开头的空字符串
\>匹配单词末尾的空字符串
  • 预定义字符
字符含义
[:alnum:]字母数字字符。在 ASCII 中,等价于 [A-Za-z0-9]
[:word:][:alnum:] 相同,但增加了下划线字符
[:alpha:]字母字符。在 ASCII 中,等价于 [A-Za-z]
[:blank:]包含空格和 Tab 字符
[:cntrl:]ASCII 的控制码。包含了 0 到 31,和 127 的 ASCII 字符
[:digit:]数字 0 到 9
[:graph:]可视字符。在 ASCII 中,它包含 33 到 126 的字符
[:lower:]小写字母。
[:punct:]标点符号字符。
[:print:]可打印的字符。等于 [:graph:] 中的所有字符,再加上空格字符。
[:space:]空白字符,包括空格,Tab,回车,换行,Vertical Tab, 和 Form Feed。在 ASCII 中, 等价于 [ \t\r\n\v\f]
[:upper:]大写字母。
[:xdigit:]用来表示十六进制数字的字符。在 ASCII 中,等价于 [0-9A-Fa-f]

命令

grep

使用 grepGlobally search a Regular Expression and Print)命令以及正则表达式查找文件内容。

常用选项有:

  • -i:忽略大小写。
  • -v:反向查找,显示不匹配的行。
  • -n:显示匹配行的行号。
  • -r:递归查找目录下的文件。
  • -l:显示匹配的文件名。
  • -c:显示匹配的行数。
  • -w:需要完全匹配单词。
  • -B NUM:显示匹配的行及其前面 NUM 行。
  • -A NUM:显示匹配的行及其后面 NUM 行。
  • -C NUM:显示匹配的行及其前后 NUM 行。
  • -E:使用扩展的正则表达式,等价于 egrep

忽略大小写查找,结果显示行号:

[root@stone ~]# grep -in path .bash_profile 
10:PATH=$PATH:$HOME/bin
12:export PATH

不显示文本中的空行:

[root@stone ~]# grep -v ^$ .bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
export DISPLAY=192.168.92.128:0.0

不显示文本中的空行及注释:

[root@stone ~]# grep -v ^$ .bash_profile | grep -v ^#
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
PATH=$PATH:$HOME/bin
export PATH
export DISPLAY=192.168.92.128:0.0

查找 PATH 关键字所在的行及其前后 3 行:

[root@stone ~]# grep -C 3 PATH .bash_profile 

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH
export DISPLAY=192.168.92.129:0.0

sed

使用 sedStream EDitor)命令以及正则表达式处理文件内容。

常用选项有:

  • -n:只输出被处理的行。
  • -i:修改原文件。
  • -r:使用扩展正则表达式。

处理文件内容通过动作实现,语法为:[n1[,n2]]动作。其中 n1n2 表示行数。动作有:

  • a:新增数据到下一行。
  • c:替换指定行。
  • d:删除指定行。
  • i:插入数据到上一行。
  • p:打印指定行。
  • s:替换指定行的某些数据。格式为 's/原字符串/新字符串/g'

在指定行后面增加一行:

[root@stone ~]# nl -ba .bash_profile | sed '12a export ORACLE_SID=stone'
    12  export PATH
export ORACLE_SID=stone
    13  export DISPLAY=192.168.92.128:0.0

替换指定行:

[root@stone ~]# nl -ba .bash_profile | sed '13c export ORACLE_SID=stone'
export ORACLE_SID=stone

删除指定行:

[root@stone ~]# nl -ba .bash_profile | sed '13d'

删除指定行到末尾所有行:

[root@stone ~]# sed '13,$d' .bash_profile 

删除最后一行:

[root@stone ~]# sed '$d' .bash_profile

去掉空行:

[root@stone ~]# sed '/^$/d' .bash_profile 
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
export DISPLAY=192.168.92.128:0.0

在指定行前面插入一行:

[root@stone ~]# nl -ba .bash_profile | sed '13i export ORACLE_SID=stone'  
export ORACLE_SID=stone
    13  export DISPLAY=192.168.92.128:0.0

打印 4-6 行:

[root@stone ~]# sed -n '4,6p' .bash_profile 
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

打印从指定字符串的行到尾行:

[root@stone ~]# sed -n '/PATH/,$p' .bash_profile 
PATH=$PATH:$HOME/bin

export PATH
export DISPLAY=192.168.92.129:0.0

替换指定数据,可以使用正则表达式进行匹配。

[root@stone ~]# sed 's/128/129/g' .bash_profile
export DISPLAY=192.168.92.129:0.0

使用 & 引用匹配的字符串:

[root@stone ~]# echo Hello World | sed 's/\w\+/[&]/g'
[Hello] [World]

以上动作都不会修改原文件,可以使用 -i 选项修改原文件:

[root@stone ~]# sed -i 's/128/129/g' .bash_profile
[root@stone ~]# tail -1 .bash_profile
export DISPLAY=192.168.92.129:0.0

printf

使用 printf 命令格式化文件内容输出。

语法:

printf FORMAT [ARGUMENT]...

其中 FORMAT

  • %[-]nss 表示字符,n 表示字符宽度,不足会以空格填充,- 表示左对齐,否则为右对齐。
  • %nii 表示整数,n 表示位数。
  • %N.nff 表示小数,N 表示整数位数,n 表示小数位数。

特殊字符有:

字符含义
"double quote
\backslash
\aalert (BEL)
\bbackspace
\cproduce no further output
\eescape
\fform feed
\nnew line
\rcarriage return
\thorizontal tab
\vvertical tab

例如对于以下文本:

[root@stone ~]# cat printf.txt 
Name     Chinese   English   Math    Average
DmTsai        80        60     92      77.33
VBird         75        55     80      70.00
Ken           60        90     70      73.33

格式化输出:

[root@stone ~]# printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt | grep -v Name)
    DmTsai    80    60    92    77.33 
     VBird    75    55    80    70.00 
       Ken    60    90    70    73.33

awk

awk 是一种编程语言,用于在 Linux 下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是 Linux 下的一个强大编程工具。它可在命令行中使用,但更多是作为脚本来使用。awk 有3个不同版本: awknawkgawk,未作特别说明,一般指 gawk

语法
awk [-F field-separator] 'program' input-file(s)

其中,program 是真正 awk 命令,必须包含在单引号中,格式为:

'BEGIN { actions }
pattern1 { actions }
............
patternN { actions }
END { actions }'

[-F field-separator] 是可选的, input-file(s) 是待处理的文件。在 awk 中,文件的每一行中,由字段分隔符分开的每一项称为一个域。通常,在不指定 [-F field-separator] 的情况下,默认的字段分隔符是空格。

运行过程:

  1. 如果 BEGIN 存在,执行它指定的 actions。
  2. 从输入文件中读取一行,称为一条输入记录。
  3. 将读入的记录分割成字段,将第 1 个字段放入变量 $1 中,第 2 个字段放入 $2,以此类推。$0 表示整条记录。
  4. 把当前输入记录依次与每一个 pattern 比较,看是否匹配,如果相匹配,就执行对应的 actions。如果不匹配,就跳过对应的 actions,直到比较完所有的 pattern。如果没有指定 actions,则使用默认的 actions,即打印当前输入记录 {print $0}
  5. 读取输入的下一行,继续重复步骤 3 和 4。
  6. 读完所有的输入行后,如果存在 END,就执行相应的 actions。
变量

program 可以使用以下变量:

变量名称描述
$n当前记录的第 n 个字段,字段间由 FS 分隔。(列内容)
$0完整的输入记录。(行内容)
NF当前记录中的字段数。(列数)
NR当前记录数。(行数)
FNR同 NR,但相对于当前文件。
FS字段分隔符(默认是任何空格)。(输入列分隔符)
RS记录分隔符(默认是一个换行符)。(输入行分隔符)
OFS输出字段分隔符(默认值是一个空格)。(输入列分隔符)
ORS输出记录分隔符(默认值是一个换行符)。(输出行分隔符)
ARGC命令行参数的数目。
ARGIND命令行中当前文件的位置(从 0 开始算)。
ARGV包含命令行参数的数组。
CONVFMT数字转换格式(默认值为 %.6g
ENVIRON环境变量关联数组。
ERRNO最后一个系统错误的描述。
FIELDWIDTHS字段宽度列表(用空格键分隔)。
FILENAME当前文件名。
IGNORECASE如果为真,则进行忽略大小写的匹配。
OFMT数字的输出格式(默认值是 %.6g)。
RLENGTHmatch 函数所匹配的字符串的长度。
RSTARTmatch 函数所匹配的字符串的第一个位置。
SUBSEP数组下标分隔符(默认值是 \034)。
运算符
运算符描述
= += -= *= /= %= ^= **=赋值
?:C条件表达式
||逻辑或
&&逻辑与
!逻辑非
~ !~匹配正则表达式和不匹配正则表达式
< <= > >= != ==关系运算符
空格字符串连接
+ -加,减
* / &乘,除与求余
^ **求幂
++ --增加或减少,作为前缀或后缀
$域引用
in数组成员
模式
名称含义
/正则表达式/使用正则表达式匹配记录
关系表达式使用关系运算符进行操作
模式匹配表达式使用运算符 ~(匹配)和 !~(不匹配)
BEGIN指定在第一条输入记录被处理之前所发生的动作,可选
Pattern1,pattern2指定行的范围,该语法不包括 BEGIN 和 END 模式
END指定在最后一条输入记录被处理之后发生的动作,可选
示例

创建待处理的文件:

[root@stone ~]# df -h > dflog
[root@stone ~]# cat dflog 
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 898M     0  898M   0% /dev
tmpfs                    910M     0  910M   0% /dev/shm
tmpfs                    910M  9.5M  901M   2% /run
tmpfs                    910M     0  910M   0% /sys/fs/cgroup
/dev/mapper/centos-root   17G  1.5G   16G   9% /
/dev/sda1               1014M  150M  865M  15% /boot
tmpfs                    182M     0  182M   0% /run/user/0

选择指定的行:

[root@stone ~]# awk 'NR==2' dflog 
devtmpfs                 898M     0  898M   0% /dev
[root@stone ~]# awk '/shm/,/boot/' dflog 
tmpfs                    910M     0  910M   0% /dev/shm
tmpfs                    910M  9.5M  901M   2% /run
tmpfs                    910M     0  910M   0% /sys/fs/cgroup
/dev/mapper/centos-root   17G  1.5G   16G   9% /
/dev/sda1               1014M  150M  865M  15% /boot
[root@stone ~]# df | awk '$2>1000000'
Filesystem              1K-blocks    Used Available Use% Mounted on
/dev/mapper/centos-root  17811456 1551392  16260064   9% /
/dev/sda1                 1038336  153572    884764  15% /boot

输出指定列:

[root@stone ~]# awk '{print $5}' dflog 
Use%
0%
0%
2%
0%
9%
15%
0%

输出指定行指定列:

[root@stone ~]# awk 'NR==7{print $5}' dflog  
15%
[root@stone ~]# awk 'NR==6,NR==7{print $1}' dflog    
/dev/mapper/centos-root
/dev/sda1

正则匹配:

[root@stone ~]# awk '/\/dev\/sda1/' dflog 
/dev/sda1               1014M  150M  865M  15% /boot
[root@stone ~]# awk '/^(\/dev\/sda|Filesystem)/' dflog
Filesystem               Size  Used Avail Use% Mounted on
/dev/sda1               1014M  150M  865M  15% /boot
[root@stone ~]# sed 's/%//g' dflog | awk '/^\/dev\/sda/{if ($5>10) print $1}'  
/dev/sda1
[root@stone ~]# sed 's/%//g' dflog | awk '/^\/dev\/sda/ && $5>10'
/dev/sda1               1014M  150M  865M  15 /boot
[root@stone ~]# sed 's/%//g' dflog | awk '/^\/dev\/sda/{print($5>10? $1" error":$1" ok")}'  
/dev/sda1 error
[root@stone ~]# awk '$6~/\/boot/{print $1}' dflog     
/dev/sda1
[root@stone ~]# awk '$1!~/tmpfs/{print $1}' dflog    
Filesystem
/dev/mapper/centos-root
/dev/sda1

使用 BEGIN 初始化变量:

[root@stone ~]# awk 'BEGIN{FS=":"}$3<5{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4

也可以使用 -F 指定分隔符:

[root@stone ~]# awk -F ':' '$3<5{print $1,$3}' /etc/passwd  
root 0
bin 1
daemon 2
adm 3
lp 4

指定输出的分隔符:

[root@stone ~]# awk 'BEGIN{OFS=":"}NR==1,NR==3{print $1,$5,$6}' dflog
Filesystem:Use%:Mounted
devtmpfs:0%:/dev
tmpfs:0%:/dev/shm

如果 program 中的内容很多,可以写在一个 awk 脚本里面,使用 -f 选项指定脚本:

原始数据:

[root@stone ~]# cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62

awk 脚本:

[root@stone ~]# cat cal.awk
#!/bin/awk -f
#运行前
BEGIN {
    math = 0
    english = 0
    computer = 0
 
    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
#运行中
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
    printf "---------------------------------------------\n"
    printf "  TOTAL:%10d %8d %8d \n", math, english, computer
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}

执行:

[root@stone ~]# awk -f cal.awk score.txt
NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL
---------------------------------------------
Marry  2143     78       84       77      239
Jack   2321     66       78       45      189
Tom    2122     48       77       71      196
Mike   2537     87       97       95      279
Bob    2415     40       57       62      159
---------------------------------------------
  TOTAL:       319      393      350 
AVERAGE:     63.80    78.60    70.00

diff

使用 diff 命令比较两个文本的内容。

常用选项有:

  • -i:忽略大小写。
  • -q:只说明文件是否相同。
  • -y:并排比较。
  • -W:并排比较时指定宽度(默认 130)。
  • -u:以合并的方式显示不同。
  • -c:显示两个文本内容及不同之处。

例如有以下两个文件:

[root@stone ~]# cat a.txt 
Hello
world
hello
CentOs
[root@stone ~]# cat b.txt 

world
Hello
CentOs
Bye

只显示两个文件是否相同:

[root@stone ~]# diff -iq a.txt b.txt  
Files a.txt and b.txt differ

显式两个文件不同之处:

[root@stone ~]# diff a.txt b.txt 
1c1
< Hello
---
> 
3c3
< hello
---
> Hello
4a5
> Bye

并排比较两个文件:

[root@stone ~]# diff -iy -W 30 a.txt b.txt 
Hello         |
world           world
hello           Hello
CentOs          CentOs
              > Bye

其中:

  • |:表示这一行内容不同。
  • <:前面文件比后面文件多一行。
  • >:后面文件比前面文件多一行。

以合并方式输出文件不同:

[root@stone ~]# diff -u a.txt b.txt  
--- a.txt       2023-07-15 20:22:07.429377286 +0800
+++ b.txt       2023-07-15 20:22:52.622380020 +0800
@@ -1,4 +1,5 @@
-Hello
+
 world
-hello
+Hello
 CentOs
+Bye

显示两个文本内容及不同之处:

[root@stone ~]# diff -c a.txt b.txt        
*** a.txt       2023-07-15 20:22:07.429377286 +0800
--- b.txt       2023-07-15 20:22:52.622380020 +0800
***************
*** 1,4 ****
! Hello
  world
! hello
  CentOs
--- 1,5 ----
! 
  world
! Hello
  CentOs
+ Bye

用户

在前面的 chmodopen in new window 命令中提到文件和目录的所有者可能是用户(user)、组(group)或者其他人(others)。本节讲述如何管理用户和组。

文件

在Linux中,每个用户都有一个唯一的用户 ID(UID)和一个所属的组 ID(GID)。用户可以属于一个或多个组,一个组可以包含一个或者多个用户,这样就可以共享文件和目录的访问权限。

与用户相关的文件有:

  • /etc/passwd:每一行表示一个用户账号信息。
[root@stone ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

每行的语法格式如下表:

用户名密码UIDGID备注信息主目录登陆 Shell
rootx00root/root/bin/bash
postfixx8989/var/spool/postfix/sbin/nologin

每个字段的意义如下表:

字段内容含义
1用户名表示登陆用户的用户名,root 用户为默认管理员,可以进行任何操作
2密码表示该用户的登陆密码,在 /etc/passwd 登陆密码都为 x,实际密码加密保存在 /etc/shadow
3UID用户 ID,Linux 为每个用户分配一个整数 ID,系统管理员 root 的 ID 为 0,1~499 为系统 ID,500~65535 为用户 ID
4GID组 ID,Linux 为每一组分配一个整数 ID
5备注信息一般无需设置
6主目录用户登陆后的默认目录
7登陆Shell用户登陆时的默认 Shell,如果为 /sbin/nologin 表示不允许登录。
  • /etc/shadow:每一行表示一个用户账号密码信息。
[root@stone ~]# cat /etc/shadow
root:$6$YJuEqeT9BxW9vX0a$ArIhJ49lVoYkqfojs5Pi2yj3TcmRhVyqoqBqLynrhFqGVabkWe238YogtSTJPSOjdrBcLx83QyzoT8AIe/AsM/::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
adm:*:18353:0:99999:7:::
lp:*:18353:0:99999:7:::
sync:*:18353:0:99999:7:::
shutdown:*:18353:0:99999:7:::
halt:*:18353:0:99999:7:::
mail:*:18353:0:99999:7:::
operator:*:18353:0:99999:7:::
games:*:18353:0:99999:7:::
ftp:*:18353:0:99999:7:::
nobody:*:18353:0:99999:7:::
systemd-network:!!:19530::::::
dbus:!!:19530::::::
polkitd:!!:19530::::::
sshd:!!:19530::::::
postfix:!!:19530::::::

每个字段的意义如下表:

字段内容含义
1用户名表示登陆用户的用户名
2密码表示加密的密码
3密码修改日期表示密码修改日期与 1970-01-01 之间的天数
4密码冻结天数表示密码修改后再修改需要等待的天数
5密码有效天数表示密码修改后可以使用的天数
6密码警告天数表示密码在有效天数到来之前向用户发出警告的天数
7密码宽限天数表示密码在有效天数到来之后可以继续使用的天数
8账号失效日期表示账号失效日期与 1970-01-01 之间的天数

与组相关的文件有:

  • /etc/group:每一行表示一个用户组信息。
[root@stone ~]# cat /etc/group
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mem:x:8:
kmem:x:9:
wheel:x:10:
cdrom:x:11:
mail:x:12:postfix
man:x:15:
dialout:x:18:
floppy:x:19:
games:x:20:
tape:x:33:
video:x:39:
ftp:x:50:
lock:x:54:
audio:x:63:
nobody:x:99:
users:x:100:
utmp:x:22:
utempter:x:35:
input:x:999:
systemd-journal:x:190:
systemd-network:x:192:
dbus:x:81:
polkitd:x:998:
ssh_keys:x:997:
sshd:x:74:
postdrop:x:90:
postfix:x:89:

每行的语法格式如下表:

用户组名称组密码GID组内成员
rootx0

每个字段的意义如下表:

字段内容含义
1用户组名称用户组名称
2组密码一般无需设置,在 /etc/group 中登陆密码都为 x,实际密码加密保存在 /etc/gshadow
3GID组 ID,Linux 为每一组分配一个整数 ID,对应 /etc/passwd 中的 GID
4组内成员组成员列表,使用逗号隔开

命令

id

使用 id 命令查看用户的 UID,GID 以及用户所属组。

常用选项有:

  • -u:只显示 UID
  • -g:只显式 GID
  • -G:显示所属组 ID
[root@stone ~]# id root
uid=0(root) gid=0(root) groups=0(root)
[root@stone ~]# id -u
0
[root@stone ~]# id -g
0
[root@stone ~]# id -G
0

groupadd

使用 groupadd 命令创建组。

常用选项有:

  • -g GID:指定 GID,/etc/group 中第 3 字段内容
  • -r:创建一个系统组,GID 在 /etc/login.defs 文件定义的 SYS_GID_MIN(201) 和 SYS_GID_MAX(999) 之间
[root@stone ~]# groupadd dba
[root@stone ~]# tail -1 /etc/group
dba:x:1001:

创建一个系统组:

[root@stone ~]# groupadd -r httpd
[root@stone ~]# tail -1 /etc/group
httpd:x:996:

groupmod

使用 groupmod 命令修改组。

常用选项有:

  • -n NEW_GROUP:修改组名,/etc/group 中第 1 字段内容
  • -g GID:修改 GID,/etc/group 中第 3 字段内容,一般不要修改 GID
[root@stone ~]# groupmod -n apache httpd
[root@stone ~]# grep apache /etc/group
apache:x:996:

groupdel

使用 groupdel 命令删除组。

常用选项有:

  • -f:强制删除用户主组。
[root@stone ~]# groupdel apache

useradd

使用 useradd 命令创建用户。

常用选项有:

  • -u UID:指定 UID,/etc/passwd 中第 3 字段内容
  • -g GID:指定 GID,/etc/passwd 中第 4 字段内容
  • -c comment:添加备注,/etc/passwd 中第 5 字段内容
  • -d homedir:设置用户主目录,/etc/passwd 中第 6 字段内容
  • -s loginshell:设置登录 Shell,/etc/passwd 中第 7 字段内容
  • -G group1,group2:设置次要组,修改 /etc/group 中相关组的第 4 字段

不使用命令选项直接增加用户,由系统指定 UID 和 GID,并创建主目录,设置登录 Shell 为 /bin/bash

[root@stone ~]# useradd stone
[root@stone ~]# grep stone /etc/passwd /etc/shadow /etc/group
/etc/passwd:stone:x:1000:1000::/home/stone:/bin/bash
/etc/shadow:stone:!!:19553:0:99999:7:::
/etc/group:stone:x:1000:
[root@stone ~]# id stone
uid=1000(stone) gid=1000(stone) groups=1000(stone)
[root@stone ~]# tail -1 /etc/group
stone:x:1000:

可以看到使用 useradd username 来创建用户时,系统默认会处理以下几个项目:

  • /etc/passwd 里面创建一行与用户相关的数据
  • /etc/shadow 里面将此用户密码相关参数填入,但是尚未有密码
  • /etc/group 里面加入一个与用户名称一模一样的组名
  • /home 目录下创建一个与用户同名的目录作为主目录,且权限为 700

创建用户后,会自动在该用户的主目录 /home/stone 下生成 .bash_logout.bash_profile.bashrc 这三个文件:

[root@stone ~]# ls -a /home/stone/
.  ..  .bash_logout  .bash_profile  .bashrc

以上操作参考的是创建用户的默认配置,使用 -D 选项可以查看创建用户时的默认配置:

[root@stone ~]# useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

以上配置来自于文件 /etc/default/useradd

[root@stone ~]# cat /etc/default/useradd 
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

其中:

  • GROUP=100:表示新创建用户的初始组 GID 为 100,这个配置不适用于 RHEL,CentOS 发行版。
  • HOME=/home:表示新创建用户的主目录在 /home 目录下。
  • INACTIVE=-1:表示密码在有效天数到来之后可以继续使用的天数,设置 /etc/shadow 第 7 个字段,指定 -1 表示密码永不失效。
  • EXPIRE=:表示账号失效日期与 1970-01-01 之间的天数,设置 /etc/shadow 第 8 个字段,一般不指定。
  • SHELL=/bin/bash:表示用户登陆时的默认 Shell,设置 /etc/passwd 第 7 个字段。
  • SKEL=/etc/skel:表示会将此目录下的文件拷贝到用户主目录。此目录下的文件有:
[root@stone ~]# ls -a /etc/skel/
.  ..  .bash_logout  .bash_profile  .bashrc
  • CREATE_MAIL_SPOOL=yes:表示在 /var/spool/mail/ 目录下为新用户创建邮箱目录。
[root@stone ~]# ll /var/spool/mail/stone
-rw-rw----. 1 stone mail 0 Jul 15 22:47 /var/spool/mail/stone

那这个邮箱目录又是在哪里指定的呢,就是 /etc/login.defs 这个文件,其还指定了创建用户时的其他配置:

[root@stone ~]# cat /etc/login.defs
#
# Please note that the parameters in this configuration file control the
# behavior of the tools from the shadow-utils component. None of these
# tools uses the PAM mechanism, and the utilities that use PAM (such as the
# passwd command) should therefore be configured elsewhere. Refer to
# /etc/pam.d/system-auth for more information.
#

# *REQUIRED*
#   Directory where mailboxes reside, _or_ name of file, relative to the
#   home directory.  If you _do_ define both, MAIL_DIR takes precedence.
#   QMAIL_DIR is for Qmail
#
#QMAIL_DIR      Maildir
MAIL_DIR        /var/spool/mail
#MAIL_FILE      .mail

# Password aging controls:
#
#       PASS_MAX_DAYS   Maximum number of days a password may be used.
#       PASS_MIN_DAYS   Minimum number of days allowed between password changes.
#       PASS_MIN_LEN    Minimum acceptable password length.
#       PASS_WARN_AGE   Number of days warning given before a password expires.
#
PASS_MAX_DAYS   99999
PASS_MIN_DAYS   0
PASS_MIN_LEN    5
PASS_WARN_AGE   7

#
# Min/max values for automatic uid selection in useradd
#
UID_MIN                  1000
UID_MAX                 60000
# System accounts
SYS_UID_MIN               201
SYS_UID_MAX               999

#
# Min/max values for automatic gid selection in groupadd
#
GID_MIN                  1000
GID_MAX                 60000
# System accounts
SYS_GID_MIN               201
SYS_GID_MAX               999

#
# If defined, this command is run when removing a user.
# It should remove any at/cron/print jobs etc. owned by
# the user to be removed (passed as the first argument).
#
#USERDEL_CMD    /usr/sbin/userdel_local

#
# If useradd should create home directories for users by default
# On RH systems, we do. This option is overridden with the -m flag on
# useradd command line.
#
CREATE_HOME     yes

# The permission mask is initialized to this value. If not specified, 
# the permission mask will be initialized to 022.
UMASK           077

# This enables userdel to remove user groups if no members exist.
#
USERGROUPS_ENAB yes

# Use SHA512 to encrypt password.
ENCRYPT_METHOD SHA512

其中:

  • MAIL_DIR:表示邮箱目录。
  • PASS_MAX_DAYS:密码修改后可以使用的天数,默认为 9999,设置 /etc/passwd 第 5 个字段。
  • PASS_MIN_DAYS:密码修改后再修改需要等待的天数,默认为 0,表示可以随时修改密码,设置 /etc/passwd 第 4 个字段。
  • PASS_MIN_LEN:密码最短长度。
  • PASS_WARN_AGE:密码在有效天数到来之前向用户发出警告的天数,默认为 7,设置 /etc/passwd 第 7 个字段。
  • UID_MIN:普通用户最小 UID,默认为 1000。
  • UID_MAX:普通用户最大 UID,默认为 60000。
  • SYS_UID_MIN:系统用户最小 UID,默认为 201。
  • SYS_UID_MAX:系统用户最大 UID,默认为 999。
  • GID_MIN:普通用户最小 GID,默认为 1000。
  • GID_MAX:普通用户最大 GID,默认为 60000。
  • SYS_GID_MIN:系统用户最小 GID,默认为 201。
  • SYS_GID_MAX:系统用户最大 GID,默认为 999。
  • CREATE_HOME:是否自动创建用户主目录。
  • UMASK:主目录的权限,077 表示创建的用户主目录的权限为 700。
  • USERGROUPS_ENAB:删除用户的同时是否删除其组,默认为 yes。
  • ENCRYPT_METHOD:密码加密算法,默认为 SHA512。

usermod

使用 usermod 命令修改用户。

常用选项有:

  • -u UID:修改 UID,/etc/passwd 中第 3 字段内容
  • -g GID:修改GID,/etc/passwd 中第 4 字段内容
  • -c comment:修改备注,/etc/passwd 中第 5 字段内容
  • -d homedir:修改用户主目录,/etc/passwd 中第 6 字段内容
  • -s loginshell:修改登录 Shell,/etc/passwd 中第 7 字段内容
  • -G group1,group2:修改次要组,修改 /etc/group 中相关组的第 4 字段
  • -a:与 -G 合用,增加次要组,修改 /etc/group 中相关组的第 4 字段
  • -L username:锁住 username 的密码,在 /etc/shadow 第 2 字段前增加 !
  • -U username:解锁 username 的密码,去掉 /etc/shadow 第 2 字段前的 !

为用户增加一个次要组:

[root@stone ~]# id stone
uid=1000(stone) gid=1000(stone) groups=1000(stone)
[root@stone ~]# usermod -G dba stone
[root@stone ~]# id stone
uid=1000(stone) gid=1000(stone) groups=1000(stone),1001(dba)
[root@stone ~]# grep dba /etc/group
dba:x:1001:stone

userdel

使用 userdel 命令删除用户。

常用选项有:

  • -r:删除用户的同时删除用户主目录和邮箱目录。
[root@stone ~]# useradd oracle
[root@stone ~]# ll -d /home/oracle/ /var/spool/mail/oracle
drwx------. 2 oracle oracle 62 Jul 16 13:11 /home/oracle/
-rw-rw----. 1 oracle mail    0 Jul 16 13:11 /var/spool/mail/oracle
[root@stone ~]# grep oracle /etc/passwd /etc/shadow /etc/group
/etc/passwd:oracle:x:1001:1002::/home/oracle:/bin/bash
/etc/shadow:oracle:!!:19554:0:99999:7:::
/etc/group:oracle:x:1002:

[root@stone ~]# userdel -r oracle
[root@stone ~]# ll -d /home/oracle/ /var/spool/mail/oracle    
ls: cannot access /home/oracle/: No such file or directory
ls: cannot access /var/spool/mail/oracle: No such file or directory
[root@stone ~]# grep oracle /etc/passwd /etc/shadow /etc/group
[root@stone ~]# 

passwd

使用 passwd 命令管理用户密码。

常用选项有:

  • -d:清空密码,使用户无需密码即可登录
  • -l:锁住用户的密码,在 /etc/shadow 第 2 字段前增加 !
  • -u:解锁用户的密码,去掉 /etc/shadow 第 2 字段前的 !
  • -e:过期密码
  • -n:修改密码冻结天数,/etc/shadow 中第 4 字段
  • -x:修改密码有效天数,/etc/shadow 中第 5 字段
  • -w:修改密码警告天数,/etc/shadow 中第 6 字段
  • -i:修改密码宽限天数,/etc/shadow 中第 7 字段,值为宽限日期与 1970-01-01 之间的天数
  • -S:列出用户密码的相关信息
  • --stdin:从标准输入读取密码

使用 root 用户可以修改所有用户密码,无需输入原始密码:

[root@stone ~]# passwd stone
Changing password for user stone.
New password: 
BAD PASSWORD: The password is shorter than 8 characters
Retype new password: 
passwd: all authentication tokens updated successfully.

从标准输入读取密码,为用户设置密码:

[root@stone ~]# echo '123456' | passwd --stdin stone
Changing password for user stone.
passwd: all authentication tokens updated successfully.

查看用户密码信息:

[root@stone ~]# passwd -S stone
stone PS 2023-07-16 0 99999 7 -1 (Password set, SHA512 crypt.)

各字段含义如下:

字段示例含义
1stone表示用户名
2PS表示用户密码状态,有三种状态:
PS = Passworded,表示已设置密码
LK = Locked ,表示已锁住密码
NP = No Password,表示无密码
32023-07-16密码修改日期,/etc/shadow 中第 3 字段
40密码冻结天数,/etc/shadow 中第 4 字段
599999密码有效天数,/etc/shadow 中第 5 字段
67密码警告天数,/etc/shadow 中第 6 字段
7-1密码宽限天数,/etc/shadow 中第 7 字段,为 -1 表示不会失效

修改密码有效天数为 90 天:

[root@stone ~]# passwd -x 90 stone
Adjusting aging data for user stone.
passwd: Success
[root@stone ~]# passwd -S stone   
stone PS 2023-07-16 0 90 7 -1 (Password set, SHA512 crypt.)

chage

使用 chagechange age)命令管理用户密码。

常用选项有:

  • -l:列出用户账号密码的详细时间参数
  • -d:修改密码修改日期,/etc/shadow 中第 3 字段,为 0 表示第一次登陆强制修改密码
  • -m:修改密码冻结天数,/etc/shadow 中第 4 字段
  • -M:修改密码有效天数,/etc/shadow 中第 5 字段
  • -W:修改密码警告天数,/etc/shadow 中第 6 字段
  • -I:修改密码宽限天数,/etc/shadow 中第 7 字段,为 -1 表示不会失效
  • -E:修改账号失效日期,/etc/shadow 中第 8 字段
[root@stone ~]# chage -l stone
Last password change                                    : Jul 16, 2023
Password expires                                        : Oct 14, 2023
Password inactive                                       : never
Account expires                                         : never
Minimum number of days between password change          : 0
Maximum number of days between password change          : 90
Number of days of warning before password expires       : 7
[root@stone ~]# chage -d 2023-06-30 -m 5 -M 180 -W 7 -I 10 -E 2023-12-30 stone
[root@stone ~]# chage -l stone
Last password change                                    : Jun 30, 2023
Password expires                                        : Dec 27, 2023
Password inactive                                       : Jan 06, 2024
Account expires                                         : Dec 30, 2023
Minimum number of days between password change          : 5
Maximum number of days between password change          : 180
Number of days of warning before password expires       : 7

不使用命令选项直接加用户名,可交互修改:

[root@stone ~]# chage stone
Changing the aging information for stone
Enter the new value, or press ENTER for the default

        Minimum Password Age [5]: 6
        Maximum Password Age [180]: 90
        Last Password Change (YYYY-MM-DD) [2023-06-30]: 2023-07-01
        Password Expiration Warning [7]: 14
        Password Inactive [10]: 
        Account Expiration Date (YYYY-MM-DD) [2023-12-30]: 
[root@stone ~]# chage -l stone
Last password change                                    : Jul 01, 2023
Password expires                                        : Sep 29, 2023
Password inactive                                       : Oct 09, 2023
Account expires                                         : Dec 30, 2023
Minimum number of days between password change          : 6
Maximum number of days between password change          : 90
Number of days of warning before password expires       : 14

su

使用 suswitch user)命令切换用户。

常用选项有:

  • -:切换用户并使用 Login Shell
  • -c:切换用户并执行命令。

root 用户使用 Login Shell 方式切换用户 stone,无须输入密码:

[root@stone ~]# su - stone
Last login: Sun Jul 16 19:24:00 CST 2023 on pts/0

stone 用户使用 Login Shell 方式切换用户 root,需要输入密码:

[stone@stone ~]$ su - root
Password: 
Last login: Mon Jul 17 21:11:22 CST 2023 from 192.168.92.1 on pts/0

stone 用户执行命令:

[root@stone ~]# su - stone -c 'pwd'
/home/stone
[root@stone ~]# 

sudo

使用 sudo 命令以其他用户的身份执行命令。

常用选项有:

  • -u:指定用户,如果不指定,则为 root

  • -l:列出用户权限

  • -b:将命令放入后台运行

ftp 用户身份创建目录(不能登录到 ftp 用户执行命令,因为 ftp 用户的 Shell 为 /sbin/nologin):

[root@stone ~]# sudo -u ftp mkdir /tmp/ftp
[root@stone ~]# ll -d /tmp/ftp
drwxr-xr-x 2 ftp ftp 6 Jul 18 10:38 /tmp/ftp

查看 root 用户权限:

[root@stone ~]# sudo -l
Matching Defaults entries for root on stone:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME
    HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE
    LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE",
    env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User root may run the following commands on stone:
    (ALL) ALL

查看 stone 用户权限:

[stone@stone ~]$ sudo -l

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for stone: 
Sorry, user stone may not run sudo on stone.

可以看到 root 用户可以执行所有命令,而 stone 用户不能运行 sudo。要使 stone 用户可以运行 sudo,需要使用 root 用户编辑配置文件 /etc/sudoers

[root@stone ~]# cat /etc/sudoers
## Sudoers allows particular users to run various commands as
## the root user, without needing the root password.
##
## Examples are provided at the bottom of the file for collections
## of related commands, which can then be delegated out to particular
## users or groups.
## 
## This file must be edited with the 'visudo' command.

## Host Aliases
## Groups of machines. You may prefer to use hostnames (perhaps using 
## wildcards for entire domains) or IP addresses instead.
# Host_Alias     FILESERVERS = fs1, fs2
# Host_Alias     MAILSERVERS = smtp, smtp2

## User Aliases
## These aren't often necessary, as you can use regular groups
## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname 
## rather than USERALIAS
# User_Alias ADMINS = jsmith, mikem


## Command Aliases
## These are groups of related commands...

## Networking
# Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool

## Installation and management of software
# Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum

## Services
# Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl start, /usr/bin/systemctl stop, /usr/bin/systemctl reload, /usr/bin/systemctl restart, /usr/bin/systemctl status, /usr/bin/systemctl enable, /usr/bin/systemctl disable

## Updating the locate database
# Cmnd_Alias LOCATE = /usr/bin/updatedb

## Storage
# Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount

## Delegating permissions
# Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp 

## Processes
# Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall

## Drivers
# Cmnd_Alias DRIVERS = /sbin/modprobe

# Defaults specification

#
# Refuse to run if unable to disable echo on the tty.
#
Defaults   !visiblepw

#
# Preserving HOME has security implications since many programs
# use it when searching for configuration files. Note that HOME
# is already set when the the env_reset option is enabled, so
# this option is only effective for configurations where either
# env_reset is disabled or HOME is present in the env_keep list.
#
Defaults    always_set_home
Defaults    match_group_by_gid

# Prior to version 1.8.15, groups listed in sudoers that were not
# found in the system group database were passed to the group
# plugin, if any. Starting with 1.8.15, only groups of the form
# %:group are resolved via the group plugin by default.
# We enable always_query_group_plugin to restore old behavior.
# Disable this option for new behavior.
Defaults    always_query_group_plugin

Defaults    env_reset
Defaults    env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults    env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults    env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults    env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults    env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"

#
# Adding HOME to env_keep may enable a user to run unrestricted
# commands via sudo.
#
# Defaults   env_keep += "HOME"

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

## Next comes the main part: which users can run what software on 
## which machines (the sudoers file can be shared between multiple
## systems).
## Syntax:
##
##      user    MACHINE=COMMANDS
##
## The COMMANDS section may have other options added to it.
##
## Allow root to run any commands anywhere 
root    ALL=(ALL)       ALL

## Allows members of the 'sys' group to run networking, software, 
## service management apps and more.
# %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS

## Allows people in group wheel to run all commands
%wheel  ALL=(ALL)       ALL

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL

## Allows members of the users group to mount and unmount the 
## cdrom as root
# %users  ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom

## Allows members of the users group to shutdown this system
# %users  localhost=/sbin/shutdown -h now

## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)
#includedir /etc/sudoers.d

其中:

  • root ALL=(ALL) ALL:可以在此行下面增加用户设置

    • root:第一部分,表示用户为 root

    • ALL=(ALL):第二部分,表示来自所有主机 ALL,可以切换为所有用户身份 (ALL)

    • ALL:第三部分,表示可以执行所有命令。

  • %wheel ALL=(ALL) ALL:可以将用户加入到 wheel 组而不需要修改此文件

    • %wheel:第一部分,表示组为 wheel

    • ALL=(ALL):第二部分,表示来自所有主机 ALL,可以切换为所有用户身份 (ALL)

    • ALL:第三部分,表示可以执行所有命令。

  • # %wheel ALL=(ALL) NOPASSWD: ALL

    • %wheel:第一部分,以 % 开头,表示组为 wheel

    • ALL=(ALL):第二部分,表示来自所有主机 ALL,可以切换为所有用户身份 (ALL)

    • NOPASSWD: ALL:第三部分,表示无需输入自身密码。

    • ALL:第四部分,表示可以执行所有命令。

stone 用户加入到 wheel 组,获取 sudo 权限:

[root@stone ~]# usermod -a -G wheel stone
[root@stone ~]# id stone
uid=1000(stone) gid=1000(stone) groups=1000(stone),10(wheel),1001(dba)
[root@stone ~]# su - stone
Last login: Tue Jul 18 10:35:50 CST 2023 on pts/0
[stone@stone ~]$ sudo -l
[sudo] password for stone: 
Matching Defaults entries for stone on stone:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME
    HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE
    LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE",
    env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User stone may run the following commands on stone:
    (ALL) ALL

或者使用 visudo 命令编辑 /etc/sudoers 文件,为某个用户授予 sudo 权限。

gpasswd

使用 gpasswd 命令管理组。

常用选项有:

  • -a:增加用户到组
  • -d:从组删除用户

wheel 组删除 stone 用户:

[root@stone ~]# id stone
uid=1000(stone) gid=1000(stone) groups=1000(stone),10(wheel),1001(dba)
[root@stone ~]# gpasswd -d stone wheel
Removing user stone from group wheel
[root@stone ~]# id stone
uid=1000(stone) gid=1000(stone) groups=1000(stone),1001(dba)

stone 用户增加到 wheel 组:

[root@stone ~]# gpasswd -a stone wheel
Adding user stone to group wheel
[root@stone ~]# id stone
uid=1000(stone) gid=1000(stone) groups=1000(stone),10(wheel),1001(dba)

w

使用 w 命令查看当前登录的用户。

[root@stone ~]# w
 13:46:36 up  4:51,  2 users,  load average: 0.04, 0.05, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.44.1     08:54    3:04m  0.17s  0.17s -bash
root     pts/1    192.168.44.1     10:47    4.00s  0.13s  0.00s w

who

使用 who 命令查看当前登录的用户。

[root@stone ~]# who
root     pts/0        2023-07-18 08:54 (192.168.44.1)
root     pts/1        2023-07-18 10:47 (192.168.44.1)

lastlog

使用 lastlog 命令查看所有用户最近登录时间。

[root@stone ~]# lastlog
Username         Port     From             Latest
root             pts/0    192.168.92.1     Tue Jul 18 20:37:45 +0800 2023
bin                                        **Never logged in**
daemon                                     **Never logged in**
adm                                        **Never logged in**
lp                                         **Never logged in**
sync                                       **Never logged in**
shutdown                                   **Never logged in**
halt                                       **Never logged in**
mail                                       **Never logged in**
operator                                   **Never logged in**
games                                      **Never logged in**
ftp                                        **Never logged in**
nobody                                     **Never logged in**
systemd-network                            **Never logged in**
dbus                                       **Never logged in**
polkitd                                    **Never logged in**
sshd                                       **Never logged in**
postfix                                    **Never logged in**
stone            pts/0                     Mon Jul 17 21:21:18 +0800 2023

磁盘

本节介绍如何管理磁盘,包括分区open in new window格式化open in new window挂载open in new window以及逻辑卷管理open in new window

简介

前面提到,在 Linux 中一切皆文件,磁盘也不例外,磁盘文件位于 /dev 目录下,格式为 /dev/sd[a-z],第一个磁盘名称为 /dev/sda,第一个磁盘的第一个分区为 /dev/sda1,以此类推。

[root@stone ~]# ll /dev/sd*
brw-rw---- 1 root disk 8, 0 Jul 18 15:20 /dev/sda
brw-rw---- 1 root disk 8, 1 Jul 18 15:20 /dev/sda1
brw-rw---- 1 root disk 8, 2 Jul 18 15:20 /dev/sda2

还可以查看 /proc/partitions 查看系统已识别的磁盘和分区:

[root@stone ~]# cat /proc/partitions
major minor  #blocks  name

   8        0   20971520 sda
   8        1    1048576 sda1
   8        2   19921920 sda2
  11        0     996352 sr0
 253        0   17821696 dm-0
 253        1    2097152 dm-1

其中 dm-0dm-1 为逻辑卷映射:

[root@stone ~]# ll /dev/mapper/centos-*
lrwxrwxrwx. 1 root root 7 Jul 19 21:05 /dev/mapper/centos-root -> ../dm-0
lrwxrwxrwx. 1 root root 7 Jul 19 21:05 /dev/mapper/centos-swap -> ../dm-1

df

使用 df 命令查看磁盘空间使用情况。

常用选项有:

  • -h:以易读的单位显示各个分区的大小
  • -i:显示各个分区的 Inode 使用情况
  • -t:指定文件系统类型
  • -T:显示文件系统类型

查看各分区空间使用情况:

[root@stone ~]# df -hT
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  898M     0  898M   0% /dev
tmpfs                   tmpfs     910M     0  910M   0% /dev/shm
tmpfs                   tmpfs     910M  9.5M  901M   2% /run
tmpfs                   tmpfs     910M     0  910M   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        17G  1.5G   16G   9% /
/dev/sda1               xfs      1014M  150M  865M  15% /boot
tmpfs                   tmpfs     182M     0  182M   0% /run/user/0

查看 xfs 文件系统的 Inode 使用情况:

[root@stone ~]# df -i -t xfs
Filesystem               Inodes IUsed   IFree IUse% Mounted on
/dev/mapper/centos-root 8910848 31866 8878982    1% /
/dev/sda1                524288   327  523961    1% /boot

du

使用 du 命令查看目录和文件的大小。当某个分区空间使用率很高时,使用 du 命令找到占用空间多的目录和文件。

常用选项有:

  • -h:以易读的单位显示各个文件的大小
  • -m:以 MB 为单位显示各个文件的大小
  • -s:显示各个目录的总大小
[root@stone ~]# du -sm /var/* | sort -n
0       /var/adm
0       /var/crash
0       /var/empty
0       /var/games
0       /var/gopher
0       /var/kerberos
0       /var/local
0       /var/lock
0       /var/mail
0       /var/nis
0       /var/opt
0       /var/preserve
0       /var/run
0       /var/tmp
0       /var/yp
1       /var/db
1       /var/spool
9       /var/log
58      /var/lib
182     /var/cache

lsblk

使用 lsblklist block devices)命令查看所有块设备信息,默认以树形显示。

常用选项有:

  • -f:显示文件系统信息
[root@stone ~]# lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda               8:0    0   20G  0 disk 
├─sda1            8:1    0    1G  0 part /boot
└─sda2            8:2    0   19G  0 part 
  ├─centos-root 253:0    0   17G  0 lvm  /
  └─centos-swap 253:1    0    2G  0 lvm  [SWAP]
sr0              11:0    1  973M  0 rom

其中:

  • NAME:设备名称
  • MAJ:MIN:主次设备号
  • RM:是否为可移动设备
  • SIZE:容量
  • RO:是否为只读设备
  • TYPE:设备类型
  • MOUNTPOINT:挂载点

查看文件系统类型及 UUID:

[root@stone ~]# lsblk -f
NAME            FSTYPE      LABEL           UUID                                   MOUNTPOINT
sda                                                                                
├─sda1          xfs                         68090631-9520-495e-a71d-b4e712110509   /boot
└─sda2          LVM2_member                 C8sDj9-yMAj-nMp7-sATx-I1ls-vU3t-woZRfK 
  ├─centos-root xfs                         05ef3cb0-4b5d-4480-baa2-2b49e861e6fa   /
  └─centos-swap swap                        6816acb0-bd23-444a-ae69-499f9a3bb3dc   [SWAP]
sr0             iso9660     CentOS 7 x86_64 2020-11-03-14-55-29-00  

blkid

使用 blkid 命令查看设备的 UUID 及文件系统类型。

[root@stone ~]# blkid
/dev/sda1: UUID="68090631-9520-495e-a71d-b4e712110509" TYPE="xfs" 
/dev/sda2: UUID="C8sDj9-yMAj-nMp7-sATx-I1ls-vU3t-woZRfK" TYPE="LVM2_member" 
/dev/sr0: UUID="2020-11-03-14-55-29-00" LABEL="CentOS 7 x86_64" TYPE="iso9660" PTTYPE="dos" 
/dev/mapper/centos-root: UUID="05ef3cb0-4b5d-4480-baa2-2b49e861e6fa" TYPE="xfs" 
/dev/mapper/centos-swap: UUID="6816acb0-bd23-444a-ae69-499f9a3bb3dc" TYPE="swap"

分区

先为虚拟机增加一块磁盘。

在 “虚拟机设置” 页面点击 “添加(A)...”。

image-20230718204721286

选择 “硬盘”,点击 “下一步”。

image-20230718204844931

保持默认的虚拟磁盘类型 “SISI(S)”,点击 “下一步”。

image-20230718204937523

选择 “创建新虚拟磁盘”,点击 “下一步”。

image-20230718205114490

指定最大磁盘大小为 1 GB,选择 “将虚拟磁盘存储为单个文件”,点击 “下一步”。

image-20230718205257257

指定磁盘文件名,点击 “完成”。

image-20230718205601906

可以看到增加了一块容量为 1 GB 的新硬盘,然后启动或重启虚拟机。如果不方便重启,可以执行以下命令让主机识别到新增加的磁盘。

[root@stone ~]# echo "- - -" > $(dirname `grep mpt /sys/class/scsi_host/host?/proc_name | cut -d ':' -f 1`)/scan

image-20230718205728889

处理分区的命令有:

  • fdisk:处理 2 TB 以下的分区,针对 MBR 分区格式,在 CentOS 7 版本可用于 GPT(实验阶段)。
  • gdisk:处理 2 TB 以上的分区,针对 GPT 分区格式。
  • parted:同时支持 MBR 和 GPT 分区格式。

fdisk

使用 fdisk 命令对 2 TB 以下的磁盘进行分区。

常用选项有:

  • -l:列出指定磁盘或者所有磁盘的分区表

列出 /dev/sda 磁盘的分区:

[root@stone ~]# fdisk -l /dev/sda    

Disk /dev/sda: 21.5 GB, 21474836480 bytes, 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000946ae

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     2099199     1048576   83  Linux
/dev/sda2         2099200    41943039    19921920   8e  Linux LVM

列出所有磁盘的分区:

[root@stone ~]# fdisk -l

Disk /dev/sda: 21.5 GB, 21474836480 bytes, 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000946ae

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     2099199     1048576   83  Linux
/dev/sda2         2099200    41943039    19921920   8e  Linux LVM

Disk /dev/sdb: 1073 MB, 1073741824 bytes, 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mapper/centos-root: 18.2 GB, 18249416704 bytes, 35643392 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mapper/centos-swap: 2147 MB, 2147483648 bytes, 4194304 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

可以看到磁盘 /dev/sdb 没有分区,下面对其进行分区。

[root@stone ~]# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table
Building a new DOS disklabel with disk identifier 0x6b830a5a.

Command (m for help): 

进入交互界面后,输入 m 获取帮助:

Command (m for help): m
Command action
   a   toggle a bootable flag
   b   edit bsd disklabel
   c   toggle the dos compatibility flag
   d   delete a partition
   g   create a new empty GPT partition table
   G   create an IRIX (SGI) partition table
   l   list known partition types
   m   print this menu
   n   add a new partition
   o   create a new empty DOS partition table
   p   print the partition table
   q   quit without saving changes
   s   create a new empty Sun disklabel
   t   change a partition's system id
   u   change display/entry units
   v   verify the partition table
   w   write table to disk and exit
   x   extra functionality (experts only)

其中:

  • p:输出分区表
  • n:新建分区
  • l:列出分区类型
  • d:删除分区
  • q:不保存退出
  • w:保存退出

先查看当前分区:

Command (m for help): p

Disk /dev/sdb: 1073 MB, 1073741824 bytes, 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x6b830a5a

   Device Boot      Start         End      Blocks   Id  System

可以看到还没有分区,新建分区:

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): 

此处需要选择分区类型:

  • primary:主分区,最多 4 个
  • extended:扩展分区,最多 1 个
  • logic:逻辑分区,在扩展分区中,可以多个。

此处创建主分区,默认也是主分区,直接回车即可:

Using default response p
Partition number (1-4, default 1): 

此处需要指定分区号,默认为 1,即 sdb1,回车即可:

Partition number (1-4, default 1): 
First sector (2048-2097151, default 2048): 

此处需要指定开始扇区号,保持默认,回车:

Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-2097151, default 2097151): 

此处需要指定结束扇区号,默认到磁盘最后,可以指定大小,如果要将整个磁盘作为 1 个分区,回车即可:

Using default value 2097151
Partition 1 of type Linux and of size 1023 MiB is set

再次查看分区:

Command (m for help): p

Disk /dev/sdb: 1073 MB, 1073741824 bytes, 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x6b830a5a

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048     2097151     1047552   83  Linux

可以看到增加了一个分区了,保存退出:

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

查看分区信息:

[root@stone ~]# lsblk 
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda               8:0    0   20G  0 disk 
├─sda1            8:1    0    1G  0 part /boot
└─sda2            8:2    0   19G  0 part 
  ├─centos-root 253:0    0   17G  0 lvm  /
  └─centos-swap 253:1    0    2G  0 lvm  [SWAP]
sdb               8:16   0    1G  0 disk 
└─sdb1            8:17   0 1023M  0 part 
sr0              11:0    1  973M  0 rom 

gdisk

使用 gdisk 命令对磁盘进行分区。

常用选项有:

  • -l:列出指定磁盘的分区表

参考上面的步骤,为虚拟机再增加一块磁盘,然后使用 gdisk 命令对磁盘进行分区。

先查看 /dev/sdc 的分区:

[root@stone ~]# gdisk -l /dev/sdc
GPT fdisk (gdisk) version 0.8.10

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.
Disk /dev/sdc: 2097152 sectors, 1024.0 MiB
Logical sector size: 512 bytes
Disk identifier (GUID): CD5C1EFB-5F02-4DB5-A2EF-D7B0485B65BB
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 2097118
Partitions will be aligned on 2048-sector boundaries
Total free space is 2097085 sectors (1024.0 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name

可以看到还没有分区,下面对 /dev/sdc 进行分区:

[root@stone ~]# gdisk /dev/sdc
GPT fdisk (gdisk) version 0.8.10

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.

Command (? for help): 

进入交互界面后,输入 ? 获取帮助:

Command (? for help): ?
b       back up GPT data to a file
c       change a partition's name
d       delete a partition
i       show detailed information on a partition
l       list known partition types
n       add a new partition
o       create a new empty GUID partition table (GPT)
p       print the partition table
q       quit without saving changes
r       recovery and transformation options (experts only)
s       sort partitions
t       change a partition's type code
v       verify disk
w       write table to disk and exit
x       extra functionality (experts only)
?       print this menu

其中:

  • p:输出分区表
  • n:新建分区
  • l:列出分区类型
  • d:删除分区
  • q:不保存退出
  • w:保存退出

先查看当前分区:

Command (? for help): p
Disk /dev/sdc: 2097152 sectors, 1024.0 MiB
Logical sector size: 512 bytes
Disk identifier (GUID): 8323B871-94ED-491D-B238-69151D276EC5
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 2097118
Partitions will be aligned on 2048-sector boundaries
Total free space is 2097085 sectors (1024.0 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name

可以看到还没有分区,新建分区:

Command (? for help): n
Partition number (1-128, default 1): 

此处需要指定分区号,默认从 1 开始,直接回车即可:

First sector (34-2097118, default = 2048) or {+-}size{KMGTP}: 

此处需要指定开始扇区号,保持默认,回车:

Last sector (2048-2097118, default = 2097118) or {+-}size{KMGTP}: 

此处需要指定结束扇区号,默认到磁盘最后,可以指定大小,如果要将整个磁盘作为 1 个分区,回车即可:

Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 

此处指定分区的文件系统,默认为 Linux filesystem,代码为 8300,保持默认,回车即可:

Changed type of partition to 'Linux filesystem'

Command (? for help): 

再次查看分区:

Command (? for help): p
Disk /dev/sdc: 2097152 sectors, 1024.0 MiB
Logical sector size: 512 bytes
Disk identifier (GUID): 8323B871-94ED-491D-B238-69151D276EC5
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 2097118
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         2097118   1023.0 MiB  8300  Linux filesystem

可以看到增加了一个分区了,保存退出:

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/sdc.
The operation has completed successfully.

查看分区信息:

[root@stone ~]# lsblk 
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda               8:0    0   20G  0 disk 
├─sda1            8:1    0    1G  0 part /boot
└─sda2            8:2    0   19G  0 part 
  ├─centos-root 253:0    0   17G  0 lvm  /
  └─centos-swap 253:1    0    2G  0 lvm  [SWAP]
sdb               8:16   0    1G  0 disk 
└─sdb1            8:17   0 1023M  0 part 
sdc               8:32   0    1G  0 disk 
└─sdc1            8:33   0 1023M  0 part 
sr0              11:0    1  973M  0 rom

parted

使用 parted 命令对磁盘进行分区。

常用选项有:

  • -l:列出所有磁盘的分区表
  • -s:脚本模式

参考上面的步骤,为虚拟机再增加一块磁盘,然后使用 parted 命令对磁盘进行分区。

先查看当前磁盘分区:

[root@stone ~]# parted -l
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sda: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  1075MB  1074MB  primary  xfs          boot
 2      1075MB  21.5GB  20.4GB  primary               lvm


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  1074MB  1073MB  primary


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdc: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name              Flags
 1      1049kB  1074MB  1073MB               Linux filesystem


Error: /dev/sdd: unrecognised disk label
Model: VMware, VMware Virtual S (scsi)                                    
Disk /dev/sdd: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags: 

Model: Linux device-mapper (linear) (dm)
Disk /dev/mapper/centos-swap: 2147MB
Sector size (logical/physical): 512B/512B
Partition Table: loop
Disk Flags: 

Number  Start  End     Size    File system     Flags
 1      0.00B  2147MB  2147MB  linux-swap(v1)


Model: Linux device-mapper (linear) (dm)
Disk /dev/mapper/centos-root: 18.2GB
Sector size (logical/physical): 512B/512B
Partition Table: loop
Disk Flags: 

Number  Start  End     Size    File system  Flags
 1      0.00B  18.2GB  18.2GB  xfs


Warning: Unable to open /dev/sr0 read-write (Read-only file system).  /dev/sr0
has been opened read-only.
Model: NECVMWar VMware IDE CDR10 (scsi)                                   
Disk /dev/sr0: 1020MB
Sector size (logical/physical): 2048B/2048B
Partition Table: msdos
Disk Flags: 

Number  Start  End     Size    Type     File system  Flags
 2      909kB  37.0MB  36.0MB  primary

可以看到磁盘 /dev/sdd 没有分区,下面对其进行分区。

[root@stone ~]# parted /dev/sdd
GNU Parted 3.1
Using /dev/sdd
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted)   

进入交互界面后,输入 help 获取帮助:

(parted) help                                                             
  align-check TYPE N                        check partition N for TYPE(min|opt) alignment
  help [COMMAND]                           print general help, or help on COMMAND
  mklabel,mktable LABEL-TYPE               create a new disklabel (partition table)
  mkpart PART-TYPE [FS-TYPE] START END     make a partition
  name NUMBER NAME                         name partition NUMBER as NAME
  print [devices|free|list,all|NUMBER]     display the partition table, available devices, free space,
        all found partitions, or a particular partition
  quit                                     exit program
  rescue START END                         rescue a lost partition near START and END
  
  resizepart NUMBER END                    resize partition NUMBER
  rm NUMBER                                delete partition NUMBER
  select DEVICE                            choose the device to edit
  disk_set FLAG STATE                      change the FLAG on selected device
  disk_toggle [FLAG]                       toggle the state of FLAG on selected device
  set NUMBER FLAG STATE                    change the FLAG on partition NUMBER
  toggle [NUMBER [FLAG]]                   toggle the state of FLAG on partition NUMBER
  unit UNIT                                set the default unit to UNIT
  version                                  display the version number and copyright information of GNU
        Parted
(parted)   

其中:

  • mklabel:设置分区类型
  • mkpart:创建分区
  • print:显示分区信息
  • quit:退出
  • rm:删除分区

先查看当前分区:

(parted) print                                                            
Error: /dev/sdd: unrecognised disk label
Model: VMware, VMware Virtual S (scsi)                                    
Disk /dev/sdd: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags:

可以看到还没有分区,先设置分区类型:

(parted) mklabel gpt                                                      
(parted) print                                                            
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdd: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start  End  Size  File system  Name  Flags

再创建分区:

(parted) help mkpart
  mkpart PART-TYPE [FS-TYPE] START END     make a partition

        PART-TYPE is one of: primary, logical, extended
        FS-TYPE is one of: btrfs, nilfs2, ext4, ext3, ext2, fat32, fat16, hfsx, hfs+, hfs, jfs, swsusp,
        linux-swap(v1), linux-swap(v0), ntfs, reiserfs, hp-ufs, sun-ufs, xfs, apfs2, apfs1, asfs,
        amufs5, amufs4, amufs3, amufs2, amufs1, amufs0, amufs, affs7, affs6, affs5, affs4, affs3, affs2,
        affs1, affs0, linux-swap, linux-swap(new), linux-swap(old)
        START and END are disk locations, such as 4GB or 10%.  Negative values count from the end of the
        disk.  For example, -1s specifies exactly the last sector.
        
        'mkpart' makes a partition without creating a new file system on the partition.  FS-TYPE may be
        specified to set an appropriate partition ID.
(parted) mkpart primary 2048s -1s                                         
Warning: You requested a partition from 1049kB to 1074MB (sectors 2048..2097151).
The closest location we can manage is 1049kB to 1074MB (sectors 2048..2097118).
Is this still acceptable to you?
Yes/No? Yes

再次查看分区:

(parted) print                                                            
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdd: 1074MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name     Flags
 1      1049kB  1074MB  1073MB               primary

可以看到增加了一个分区了,直接退出:

(parted) quit                                                             
Information: You may need to update /etc/fstab.

查看分区信息:

[root@stone ~]# lsblk                                                     
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda               8:0    0   20G  0 disk 
├─sda1            8:1    0    1G  0 part /boot
└─sda2            8:2    0   19G  0 part 
  ├─centos-root 253:0    0   17G  0 lvm  /
  └─centos-swap 253:1    0    2G  0 lvm  [SWAP]
sdb               8:16   0    1G  0 disk 
└─sdb1            8:17   0 1023M  0 part 
sdc               8:32   0    1G  0 disk 
└─sdc1            8:33   0 1023M  0 part 
sdd               8:48   0    1G  0 disk 
└─sdd1            8:49   0 1023M  0 part 
sr0              11:0    1  973M  0 rom

还可以直接在命令行使用 parted 命令执行分区操作,比如上面的分区操作可以使用以下命令完成:

[root@stone ~]# parted -s /dev/sdd mklabel gpt 
[root@stone ~]# parted -s /dev/sdd mkpart primary 2048s -1s
[root@stone ~]# parted -s /dev/sdd print

格式化

对磁盘进行分区后,需要指定文件类型对其进行格式化,创建文件系统。

常用的文件类型如下:

TypeFile systemAttributes and use cases
Disk or local FSXFSXFS is the default file system in RHEL. Because it lays out files as extents, it is less vulnerable to fragmentation than ext4. Red Hat recommends deploying XFS as your local file system unless there are specific reasons to do otherwise: for example, compatibility or corner cases around performance.
Disk or local FSext4ext4 has the benefit of longevity in Linux. Therefore, it is supported by almost all Linux applications. In most cases, it rivals XFS on performance. ext4 is commonly used for home directories.
Network or client-and-server FSNFSUse NFS to share files between multiple systems on the same network.
Network or client-and-server FSSMBUse SMB for file sharing with Microsoft Windows systems.
Shared storage or shared disk FSGFS2GFS2 provides shared write access to members of a compute cluster. The emphasis is on stability and reliability, with the functional experience of a local file system as possible. SAS Grid, Tibco MQ, IBM Websphere MQ, and Red Hat Active MQ have been deployed successfully on GFS2.
Volume-managing FSStratis (Technology Preview)Stratis is a volume manager built on a combination of XFS and LVM. The purpose of Stratis is to emulate capabilities offered by volume-managing file systems like Btrfs and ZFS. It is possible to build this stack manually, but Stratis reduces configuration complexity, implements best practices, and consolidates error information.

对于本地文件系统,建议:

  • XFS:CentOS 7 默认文件系统类型。
  • ext4:CentOS 6 默认文件系统类型。

mkfs.xfs

使用 mkfs.xfs 命令将分区格式化为 XFS 文件系统类型。

常用选项有:

  • -L:为文件系统指定一个 Label,不超过 12 个字符。

格式化前查看分区信息:

[root@stone ~]# lsblk -f /dev/sdb
NAME   FSTYPE LABEL UUID MOUNTPOINT
sdb                      
└─sdb1

格式化:

[root@stone ~]# mkfs.xfs /dev/sdb1
meta-data=/dev/sdb1              isize=512    agcount=4, agsize=65472 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=261888, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=855, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

格式化后查看分区信息:

[root@stone ~]# lsblk -f /dev/sdb 
NAME   FSTYPE LABEL UUID                                 MOUNTPOINT
sdb                                                      
└─sdb1 xfs          daf8b47d-842a-476d-8e18-5da4a4a15d6d

挂载

将分区格式化为 XFS 文件系统后,需要挂载到空目录才能使用。

mount

使用 mount 命令挂载文件系统到指定目录。

常用选项有:

  • -a:挂载文件 /etc/fstab 中的所有文件系统。
  • -t:指定挂载的文件系统类型,在 CentOS 7 可以不指定,系统自动识别。
  • -n:不会将挂载信息写入到 /etc/mtab,当 /etc 目录只读时需使用此选项。
  • -o:指定挂载参数,常用参数有:
    • atimenoatime:读取文件时是否更新其 atime
    • rorw:挂载文件系统为只读或可读写
    • remount:重新挂载

挂载前查看当前的挂载情况:

[root@stone ~]# mount | grep /dev/sd
/dev/sda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,noquota)

创建目录并挂载:

[root@stone ~]# mkdir -p /data/sdb1
[root@stone ~]# mount /dev/sdb1 /data/sdb1/

再次查看挂载情况:

[root@stone ~]# mount | grep /dev/sd       
/dev/sda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/sdb1 on /data/sdb1 type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
[root@stone ~]# lsblk -f /dev/sdb
NAME   FSTYPE LABEL UUID                                 MOUNTPOINT
sdb                                                      
└─sdb1 xfs          daf8b47d-842a-476d-8e18-5da4a4a15d6d /data/sdb1
[root@stone ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 898M     0  898M   0% /dev
tmpfs                    910M     0  910M   0% /dev/shm
tmpfs                    910M  9.6M  901M   2% /run
tmpfs                    910M     0  910M   0% /sys/fs/cgroup
/dev/mapper/centos-root   17G  1.5G   16G   9% /
/dev/sda1               1014M  150M  865M  15% /boot
tmpfs                    182M     0  182M   0% /run/user/0
/dev/sdb1               1020M   33M  988M   4% /data/sdb1

还可以将光盘挂载到指定目录:

[root@stone ~]# mount /dev/sr0 /media/
mount: /dev/sr0 is write-protected, mounting read-only
[root@stone ~]# ls /media/
CentOS_BuildTag  EULA  images    LiveOS    repodata              RPM-GPG-KEY-CentOS-Testing-7
EFI              GPL   isolinux  Packages  RPM-GPG-KEY-CentOS-7  TRANS.TBL

挂载文件系统到指定目录后,就可以对其进行写入和读取了,但是如果重启了主机,就会发现之前挂载的文件系统不见了,如果要使用,就得再挂载一下。此时就需要使用 /etc/fstab 文件了,将挂载信息写入到此文件中,主机在启动的时候就会读取该文件,并进行挂载。

[root@stone ~]# cat /etc/fstab 

#
# /etc/fstab
# Created by anaconda on Thu Jun 22 20:37:31 2023
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=68090631-9520-495e-a71d-b4e712110509 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

其中:

  • /dev/mapper/centos-root:第 1 项,指定需要挂载的对象,可以是分区名称,UUID 或者 LABEL。
  • /:第 2 项,指定挂载目录。
  • xfs:第 3 项,指定文件系统类型。
  • defaults:第 4 项,指定挂载参数,一般为 defaults,表示:rw,suid,dev,exec,auto,nouser 和 async。
  • 0:第 5 项,指定是否支持 dump 备份,一般无需支持,保持为 0
  • 0:第 6 项,指定是否需要在开机时使用 fsck 检查文件系统,不适用于 XFS 文件系统,保持为 0

将新创建的文件系统加入到 /etc/fstab 文件中,在最后面添加一行:

[root@stone ~]# vi /etc/fstab 

#
# /etc/fstab
# Created by anaconda on Thu Jun 22 20:37:31 2023
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=68090631-9520-495e-a71d-b4e712110509 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
/dev/sdb1              /data/sdb1/              xfs     defaults        0 0

然后挂载该文件中的所有文件系统:

[root@stone ~]# mount -a

查看挂载情况:

[root@stone ~]# mount | grep /dev/sdb
/dev/sdb1 on /data/sdb1 type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
[root@stone ~]# df -h | grep /dev/sdb
/dev/sdb1               1020M   33M  988M   4% /data/sdb1

umount

使用 umount 卸载文件系统。

常用选项有:

  • -f:强制卸载,经常用于无法访问的 NFS 文件系统。
  • -l:当使用 -f 失败时,可以使用此选项。

卸载前面挂载的文件系统:

[root@stone ~]# umount /data/sdb1

卸载的时候,不能有进程使用该文件系统,否则需要终止相关进程或者使用 -l 选项才能卸载。

[root@stone ~]# cd /data/sdb1/
[root@stone sdb1]# umount /data/sdb1
umount: /data/sdb1: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))
[root@stone sdb1]# umount -l /data/sdb1

使用 umount 命令卸载只是临时卸载,要永久生效,需要删除或者注释 /etc/fstab 中对应条目。

逻辑卷管理

考虑如下情况,将一个 100 GB 的分区格式化并挂载到某个目录后,随着数据量的增加,会将该分区写满,那么该如何应对这种数据不断增长的情况呢。是重新挂载一个 200 GB 的分区,然后将原分区的数据拷贝到新分区吗,当然不需要这么麻烦。在实际工作中,都会使用逻辑卷管理(Logical Volume Manager LVM)来处理这种需求,弹性调整文件系统的大小。

LVM 包括:

  • PV(Physical Volume):物理卷,由分区创建。
  • VG(Volume Group):卷组,由多个 PV 组成,并划分成多个 PE(Physical Extent),作为逻辑卷的最小存储单元。
  • LV(Logical Volume):逻辑卷,由多个 PE 组成。

创建逻辑卷的步骤:

  1. 创建分区,使用 gdisk命令
  2. 创建 PV,使用 pvcreate 命令
  3. 创建 VG,使用 vgcreate 命令
  4. 创建 LV,使用 lvcreate 命令
  5. 格式化和挂载,使用 mkfs.xfsmount 命令

image-20230723121115787

创建分区

为虚拟机增加 2 块 1 GB 磁盘,使用 gdiskopen in new window 命令创建分区。

创建分区前:

[root@stone ~]# lsblk 
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda               8:0    0   20G  0 disk 
├─sda1            8:1    0    1G  0 part /boot
└─sda2            8:2    0   19G  0 part 
  ├─centos-root 253:0    0   17G  0 lvm  /
  └─centos-swap 253:1    0    2G  0 lvm  [SWAP]
sdb               8:16   0    1G  0 disk 
└─sdb1            8:17   0 1023M  0 part /data/sdb1
sdc               8:32   0    1G  0 disk 
└─sdc1            8:33   0 1023M  0 part 
sdd               8:48   0    1G  0 disk 
└─sdd1            8:49   0 1023M  0 part 
sde               8:64   0    1G  0 disk 
sdf               8:80   0    1G  0 disk 
sr0              11:0    1  973M  0 rom 

使用 gdisk 命令创建分区,与之前不同的是,需要指定分区编码为 8e00

Hex code or GUID (L to show codes, Enter = 8300): 8e00
Changed type of partition to 'Linux LVM'

创建分区后:

[root@stone ~]# lsblk 
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda               8:0    0   20G  0 disk 
├─sda1            8:1    0    1G  0 part /boot
└─sda2            8:2    0   19G  0 part 
  ├─centos-root 253:0    0   17G  0 lvm  /
  └─centos-swap 253:1    0    2G  0 lvm  [SWAP]
sdb               8:16   0    1G  0 disk 
└─sdb1            8:17   0 1023M  0 part /data/sdb1
sdc               8:32   0    1G  0 disk 
└─sdc1            8:33   0 1023M  0 part 
sdd               8:48   0    1G  0 disk 
└─sdd1            8:49   0 1023M  0 part 
sde               8:64   0    1G  0 disk 
└─sde1            8:65   0 1023M  0 part 
sdf               8:80   0    1G  0 disk 
└─sdf1            8:81   0 1023M  0 part 
sr0              11:0    1  973M  0 rom 

创建 PV

相关命令有:

  • pvcreate:创建 PV
  • pvscan:列出 PV
  • pvdisplay:列出 PV 详细信息
  • pvremove:删除 PV
[root@stone ~]# pvscan 
  PV /dev/sda2   VG centos          lvm2 [<19.00 GiB / 0    free]
  Total: 1 [<19.00 GiB] / in use: 1 [<19.00 GiB] / in no VG: 0 [0   ]
  
[root@stone ~]# pvcreate /dev/sde1 /dev/sdf1
  Physical volume "/dev/sde1" successfully created.
  Physical volume "/dev/sdf1" successfully created.
  
[root@stone ~]# pvscan 
  PV /dev/sda2   VG centos          lvm2 [<19.00 GiB / 0    free]
  PV /dev/sde1                      lvm2 [1022.98 MiB]
  PV /dev/sdf1                      lvm2 [1022.98 MiB]
  Total: 3 [20.99 GiB] / in use: 1 [<19.00 GiB] / in no VG: 2 [<2.00 GiB]
  
[root@stone ~]# pvdisplay /dev/sde1
  "/dev/sde1" is a new physical volume of "1022.98 MiB"
  --- NEW Physical volume ---
  PV Name               /dev/sde1
  VG Name               
  PV Size               1022.98 MiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               v7Fnm3-gt9R-lX5v-9pVz-26A2-oed7-YjoBL1
   
[root@stone ~]# pvdisplay /dev/sdf1
  "/dev/sdf1" is a new physical volume of "1022.98 MiB"
  --- NEW Physical volume ---
  PV Name               /dev/sdf1
  VG Name               
  PV Size               1022.98 MiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               xP932c-wx0f-yQOp-Gg9p-qTry-k7zv-SsC38c

由于 PE 是在创建 VG 时指定,故此时看到的 PV 里面的 PE 都是 0

创建 VG

基于 PV 创建 VG ,相关命令有:

  • vgcreate:创建 VG,常用选项有:
    • -s:指定 PE 大小,默认为 4 MB。
  • vgscan:列出 VG
  • vgdisplay:列出 VG 详细信息
  • vgextend:增加 PV 到 VG
  • vgreduce:从 VG 中移除 PV
  • vgchange:修改 VG 属性,常用选项有:
    • -a:指定 VG 是否激活,如果要删除该 VG,则需指定为 n
  • vgremove:删除 VG
[root@stone ~]# vgscan 
  Reading volume groups from cache.
  Found volume group "centos" using metadata type lvm2
  
[root@stone ~]# vgcreate stonevg /dev/sde1 /dev/sdf1
  Volume group "stonevg" successfully created
  
[root@stone ~]# vgscan 
  Reading volume groups from cache.
  Found volume group "stonevg" using metadata type lvm2
  Found volume group "centos" using metadata type lvm2
  
[root@stone ~]# vgdisplay stonevg
  --- Volume group ---
  VG Name               stonevg
  System ID             
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               1.99 GiB
  PE Size               4.00 MiB
  Total PE              510
  Alloc PE / Size       0 / 0   
  Free  PE / Size       510 / 1.99 GiB
  VG UUID               vYEARm-IZij-B6N1-yWeS-oGF1-z2qM-BuBzzg

可以看到 stonevg 的大小约为 2 GB,PE 大小为 4 MB,共有 510 个 PE,目前还没有分配给 LV。

此时使用 pvdisplay 查看之前创建的 PV:、

[root@stone ~]# pvdisplay /dev/sde1
  --- Physical volume ---
  PV Name               /dev/sde1
  VG Name               stonevg
  PV Size               1022.98 MiB / not usable 2.98 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              255
  Free PE               255
  Allocated PE          0
  PV UUID               v7Fnm3-gt9R-lX5v-9pVz-26A2-oed7-YjoBL1
   
[root@stone ~]# pvdisplay /dev/sdf1
  --- Physical volume ---
  PV Name               /dev/sdf1
  VG Name               stonevg
  PV Size               1022.98 MiB / not usable 2.98 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              255
  Free PE               255
  Allocated PE          0
  PV UUID               xP932c-wx0f-yQOp-Gg9p-qTry-k7zv-SsC38c

可以看到这两个 PV 的 VG Name 为 stonevg,PE Size 为 4 MB,Total PE 为 255。

创建 LV

基于 VG 创建 LV,相关命令有:

  • lvcreate:创建 LV,常用选项有:
    • -L:指定 LV 大小,单位可以是 M,G,T 等
    • -l:指定 LV 大小,后面是 PE 个数
    • -n:指定 LV 名称
  • lvscan:列出 LV
  • lvdisplay:列出 LV 详细信息
  • lvextend:扩展 LV
  • lvreduce:缩小 LV
  • lvresize:调整 LV 容量
  • lvremove:删除 LV
[root@stone ~]# lvscan 
  ACTIVE            '/dev/centos/swap' [2.00 GiB] inherit
  ACTIVE            '/dev/centos/root' [<17.00 GiB] inherit
  
[root@stone ~]# lvcreate -L 1G -n stonelv1 stonevg    
  Logical volume "stonelv1" created.
  
[root@stone ~]# lvcreate -L 1G -n stonelv2 stonevg
  Volume group "stonevg" has insufficient free space (254 extents): 256 required.
[root@stone ~]# lvcreate -l 254 -n stonelv2 stonevg   
  Logical volume "stonelv2" created.
  
[root@stone ~]# lvscan 
  ACTIVE            '/dev/stonevg/stonelv1' [1.00 GiB] inherit
  ACTIVE            '/dev/stonevg/stonelv2' [1016.00 MiB] inherit
  ACTIVE            '/dev/centos/swap' [2.00 GiB] inherit
  ACTIVE            '/dev/centos/root' [<17.00 GiB] inherit
  
[root@stone ~]# lvdisplay /dev/stonevg/stonelv1
  --- Logical volume ---
  LV Path                /dev/stonevg/stonelv1
  LV Name                stonelv1
  VG Name                stonevg
  LV UUID                Oo3125-3ryt-TXXn-CjlR-6x98-x3XZ-3kheYf
  LV Write Access        read/write
  LV Creation host, time stone, 2023-07-23 13:01:52 +0800
  LV Status              available
  # open                 0
  LV Size                1.00 GiB
  Current LE             256
  Segments               2
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     8192
  Block device           253:2
   
[root@stone ~]# lvdisplay /dev/stonevg/stonelv2
  --- Logical volume ---
  LV Path                /dev/stonevg/stonelv2
  LV Name                stonelv2
  VG Name                stonevg
  LV UUID                MmptiA-YNx5-W0n3-l011-qbge-Rg00-ZSKIzY
  LV Write Access        read/write
  LV Creation host, time stone, 2023-07-23 13:04:34 +0800
  LV Status              available
  # open                 0
  LV Size                1016.00 MiB
  Current LE             254
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     8192
  Block device           253:3

此时查看 VG 可以看到已经将所有 PE 分配给了 LV:

[root@stone ~]# vgdisplay stonevg
  --- Volume group ---
  VG Name               stonevg
  System ID             
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  3
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                2
  Open LV               2
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               1.99 GiB
  PE Size               4.00 MiB
  Total PE              510
  Alloc PE / Size       510 / 1.99 GiB
  Free  PE / Size       0 / 0   
  VG UUID               vYEARm-IZij-B6N1-yWeS-oGF1-z2qM-BuBzzg

格式化和挂载

使用 mkfs.xfsmount 命令进行格式化和挂载。

[root@stone ~]# mkfs.xfs /dev/stonevg/stonelv1
meta-data=/dev/stonevg/stonelv1  isize=512    agcount=4, agsize=65536 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=262144, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

[root@stone ~]# mkfs.xfs /dev/stonevg/stonelv2
meta-data=/dev/stonevg/stonelv2  isize=512    agcount=4, agsize=65024 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=260096, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=855, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

[root@stone ~]# mkdir /data/stonelv1 /data/stonelv2
[root@stone ~]# mount /dev/stonevg/stonelv1 /data/stonelv1
[root@stone ~]# mount /dev/stonevg/stonelv2 /data/stonelv2

[root@stone ~]# df -h
Filesystem                    Size  Used Avail Use% Mounted on
devtmpfs                      898M     0  898M   0% /dev
tmpfs                         910M     0  910M   0% /dev/shm
tmpfs                         910M  9.6M  901M   2% /run
tmpfs                         910M     0  910M   0% /sys/fs/cgroup
/dev/mapper/centos-root        17G  1.5G   16G   9% /
/dev/sdb1                    1020M   33M  988M   4% /data/sdb1
/dev/sda1                    1014M  150M  865M  15% /boot
tmpfs                         182M     0  182M   0% /run/user/0
/dev/mapper/stonevg-stonelv1 1014M   33M  982M   4% /data/stonelv1
/dev/mapper/stonevg-stonelv2 1013M   33M  981M   4% /data/stonelv2

扩展 LV

创建逻辑卷的步骤:

  1. 创建分区,使用 gdisk命令
  2. 创建 PV,使用 pvcreate 命令
  3. 扩展 VG,使用 vgextend 命令
  4. 扩展 LV,使用 lvextend 命令
  5. 扩展文件系统,使用 xfs_growfs 命令

image-20230723133655119

假设扩展逻辑卷 stonelv2,由于此时卷组 stonevg 没有剩余空间了,故需要先增加磁盘,再分区,创建物理卷,然后扩展卷组,才能扩展逻辑卷,最后再扩展文件系统。

为虚拟机增加 1 块 1 GB 磁盘,使用 gdiskopen in new window 命令创建分区,结果如下:

[root@stone ~]# lsblk
NAME                 MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                    8:0    0   20G  0 disk 
├─sda1                 8:1    0    1G  0 part /boot
└─sda2                 8:2    0   19G  0 part 
  ├─centos-root      253:0    0   17G  0 lvm  /
  └─centos-swap      253:1    0    2G  0 lvm  [SWAP]
sdb                    8:16   0    1G  0 disk 
└─sdb1                 8:17   0 1023M  0 part /data/sdb1
sdc                    8:32   0    1G  0 disk 
└─sdc1                 8:33   0 1023M  0 part 
sdd                    8:48   0    1G  0 disk 
└─sdd1                 8:49   0 1023M  0 part 
sde                    8:64   0    1G  0 disk 
└─sde1                 8:65   0 1023M  0 part 
  └─stonevg-stonelv1 253:2    0    1G  0 lvm  /data/stonelv1
sdf                    8:80   0    1G  0 disk 
└─sdf1                 8:81   0 1023M  0 part 
  ├─stonevg-stonelv1 253:2    0    1G  0 lvm  /data/stonelv1
  └─stonevg-stonelv2 253:3    0 1016M  0 lvm  /data/stonelv2
sdg                    8:96   0    1G  0 disk 
└─sdg1                 8:97   0 1023M  0 part 
sr0                   11:0    1  973M  0 rom 

使用 pvcreate 命令创建 PV:

[root@stone ~]# pvcreate /dev/sdg1
  Physical volume "/dev/sdg1" successfully created.
[root@stone ~]# pvdisplay /dev/sdg1
  "/dev/sdg1" is a new physical volume of "1022.98 MiB"
  --- NEW Physical volume ---
  PV Name               /dev/sdg1
  VG Name               
  PV Size               1022.98 MiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               ZYy1WB-DBA3-mdvp-rQ2d-NJVs-BUrg-Vax5pH

使用 vgextend 命令扩展 VG:

[root@stone ~]# vgextend stonevg /dev/sdg1
  Volume group "stonevg" successfully extended
  
[root@stone ~]# vgdisplay stonevg
  --- Volume group ---
  VG Name               stonevg
  System ID             
  Format                lvm2
  Metadata Areas        3
  Metadata Sequence No  4
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                2
  Open LV               2
  Max PV                0
  Cur PV                3
  Act PV                3
  VG Size               <2.99 GiB
  PE Size               4.00 MiB
  Total PE              765
  Alloc PE / Size       510 / 1.99 GiB
  Free  PE / Size       255 / 1020.00 MiB
  VG UUID               vYEARm-IZij-B6N1-yWeS-oGF1-z2qM-BuBzzg

可以看到增加了 255 个 PE。

使用 lvextend 命令扩展 LV,常用选项有:

  • -L:指定 LV 大小,单位可以是 M,G,T 等,使用 + 表示增加多少空间,不使用则表示扩展到多少空间
  • -l:指定 LV 大小,后面是 PE 个数,使用 + 表示增加多少 PE,不使用则表示扩展到多少 PE
[root@stone ~]# lvextend -l +255 /dev/stonevg/stonelv2
  Size of logical volume stonevg/stonelv2 changed from 1016.00 MiB (254 extents) to <1.99 GiB (509 extents).
  Logical volume stonevg/stonelv2 successfully resized.
  
[root@stone ~]# lvdisplay /dev/stonevg/stonelv2
  --- Logical volume ---
  LV Path                /dev/stonevg/stonelv2
  LV Name                stonelv2
  VG Name                stonevg
  LV UUID                MmptiA-YNx5-W0n3-l011-qbge-Rg00-ZSKIzY
  LV Write Access        read/write
  LV Creation host, time stone, 2023-07-23 13:04:34 +0800
  LV Status              available
  # open                 1
  LV Size                <1.99 GiB
  Current LE             509
  Segments               2
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     8192
  Block device           253:3

使用 xfs_growfs 命令扩展文件系统:

[root@stone ~]# df -h /data/stonelv2
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/stonevg-stonelv2 1013M   33M  981M   4% /data/stonelv2
[root@stone ~]# xfs_growfs /data/stonelv2
meta-data=/dev/mapper/stonevg-stonelv2 isize=512    agcount=4, agsize=65024 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0 spinodes=0
data     =                       bsize=4096   blocks=260096, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal               bsize=4096   blocks=855, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 260096 to 521216
[root@stone ~]# df -h /data/stonelv2     
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/stonevg-stonelv2  2.0G   33M  2.0G   2% /data/stonelv2

可以看到 /data/stonelv2 从 1 GB 扩展到 2 GB。

总结

对于逻辑卷管理涉及到的阶段和命令如下表:

PVVGLVXFSext4
scanpvscanvgscanlvscanlsblk, blkidlsblk, blkid
createpvcreatevgcreatelvcreatemkfs.xfsmkfs.ext4
displaypvdisplayvgdisplaylvdisplaydf, mountdf, mount
extendvgextendlvextend (lvresize)xfs_growfsresize2fs
reducevgreducelvreduce (lvresize)resize2fs
removepvremovevgremovelvremoveumountumount
resizelvresizexfs_growfsresize2fs
changepvchangevgchangelvchange/etc/fstab, remount/etc/fstab, remount

内存

Linux 的内存管理非常复杂,本文不涉及内存管理的原理及体系,只说明在实际工作中如何查看内存以及调整内存。

内存信息

这里只介绍查看系统整体内存使用情况的命令,对于各个进程使用内存的情况,将在进程open in new window章节详细介绍。

free

使用 free 命令查看系统内存使用情况。

  • -h:以易读方式显示内存大小
  • -k:以 KB 为单位
  • -m:以 MB 为单位
  • -g:以 GB 为单位
  • -wbufferscache 分开显示
  • -s:指定刷新间隔秒数,连续显示
  • -c:与 -s 配合,指定刷新次数
[root@stone ~]# free -m -w
              total        used        free      shared     buffers       cache   available
Mem:           3931        1863        1496          14           2         569        1835
Swap:          2047           0        2047

其中:

  • 第 2 行显示物理内存使用情况,为 /proc/meminfo 的相关内容项,包括:
    • total:总内存,为 /proc/meminfo 中的 MemTotal
    • used:已用内存,为 total - free - buffers - cache
    • free:未使用内存,为 /proc/meminfo 中的 MemFree
    • shared:被 tmpfs 使用的内存,为 /proc/meminfo 中的 Shmem
    • buff:内核缓冲(kernel buffers),为 /proc/meminfo 中的 Buffers
    • cache:是页面缓存(page cache)和 slabs,为 /proc/meminfo 中的 CachedSReclaimable
    • available:可用物理内存,为 /proc/meminfo 中的 MemAvailable
  • 第 3 行显示 SWAP 使用情况,包括:
    • total:总 SWAP,为 /proc/meminfo 中的 SwapTotal
    • used:已用 SWAP,为 total - free
    • free:未使用 SWAP,为 /proc/meminfo 中的 SwapFree

直接查看文件 /proc/meminfo 获取内存详细信息:

[root@stone ~]# cat /proc/meminfo 
MemTotal:        4026164 kB
MemFree:         1528584 kB
MemAvailable:    1876072 kB
Buffers:            2112 kB
Cached:           546068 kB
SwapCached:            0 kB
Active:           838756 kB
Inactive:         387320 kB
Active(anon):     678660 kB
Inactive(anon):    13592 kB
Active(file):     160096 kB
Inactive(file):   373728 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:        677896 kB
Mapped:            93216 kB
Shmem:             14356 kB
Slab:             106496 kB
SReclaimable:      37520 kB
SUnreclaim:        68976 kB
KernelStack:        7808 kB
PageTables:        23768 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     3585940 kB
Committed_AS:    2018728 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      188972 kB
VmallocChunk:   34359310332 kB
Percpu:            25600 kB
HardwareCorrupted:     0 kB
AnonHugePages:    532480 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:     512
HugePages_Free:      482
HugePages_Rsvd:      432
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       98112 kB
DirectMap2M:     4096000 kB
DirectMap1G:     2097152 kB

SWAP

使用 lsblk 命令查看所有块设备信息:

[root@stone ~]# lsblk 
NAME            MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
fd0               2:0    1   4K  0 disk 
sda               8:0    0  40G  0 disk 
├─sda1            8:1    0   1G  0 part /boot
└─sda2            8:2    0  39G  0 part 
  ├─centos-root 253:0    0  37G  0 lvm  /
  └─centos-swap 253:1    0   2G  0 lvm  [SWAP]
sr0              11:0    1   1G  0 rom 

可以看到有一个 SWAP 分区,这个分区是在安装系统时创建的。在物理内存不足时,可以使用 SWAP 分区来临时存放内存中暂不使用的数据,相当于临时扩展了物理内存。由于 SWAP 分区是位于磁盘上面的,其速度远低于内存,基于性能考虑,应尽量避免系统使用到 SWAP。但在某些时候,由于物理内存不足,比如云主机,为了避免出现 OOM 的情况,可以考虑添加 SWAP 分区。

添加 SWAP 分区可以使用分区来添加,也可以直接使用文件。在实际工作中,往往没有多余的分区,更多是通过使用文件来添加。步骤如下:

  1. 使用 dd 命令创建一个 1 GB 的文件
[root@stone ~]# dd if=/dev/zero of=/root/swap bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 2.90622 s, 369 MB/s
[root@stone ~]# ll -h /root/swap
-rw-r--r--. 1 root root 1.0G Jul 25 20:27 /root/swap

其中:

  • if:指定输入文件(Input File),/dev/zero 提供无限连续不断的空的数据流
  • of:指定输出文件(Output File)
  • bs:指定输入和输出的块大小(Block Size)
  • count:指定块数量
  1. 使用 mkswap 命令将 /root/swap 文件格式化为 SWAP 格式
[root@stone ~]# mkswap /root/swap
Setting up swapspace version 1, size = 1048572 KiB
no label, UUID=46a4a37a-b4f0-413e-b0ac-d7260219ba0d
  1. 使用 swapon 命令启用 /root/swap,然后使用 swapon -s 命令查看
[root@stone ~]# swapon /root/swap 
swapon: /root/swap: insecure permissions 0644, 0600 suggested.
[root@stone ~]# swapon -s
Filename                                Type            Size    Used    Priority
/dev/dm-1                               partition       2097148 0       -2
/root/swap                              file    1048572 0       -3
  1. 添加到 /etc/fstab 文件中
[root@stone ~]# vi /etc/fstab

#
# /etc/fstab
# Created by anaconda on Thu Jun 22 20:37:31 2023
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=68090631-9520-495e-a71d-b4e712110509 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
/dev/sdb1              /data/sdb1/              xfs     defaults        0 0
/root/swap              swap                    swap    defaults        0 0
  1. 可以使用 swapoff 命令禁用 /root/swap,然后使用 swapon -a 命令挂载 /etc/fstab 文件中的 “swap” 文件系统
[root@stone ~]# swapoff /root/swap
[root@stone ~]# swapon -s
Filename                                Type            Size    Used    Priority
/dev/dm-1                               partition       2097148 0       -2
[root@stone ~]# swapon -a
swapon: /root/swap: insecure permissions 0644, 0600 suggested.
[root@stone ~]# swapon -s
Filename                                Type            Size    Used    Priority
/dev/dm-1                               partition       2097148 0       -2
/root/swap                              file    1048572 0       -3

进程

执行文件系统上的程序后,系统会将其读入到内存中,作为进程来运行。

进程管理

在 Windows 上,可以通过任务管理器图像界面来管理进程,而在 Linux 上,一般通过命令来进行管理。

ps

使用 psprocess status)命令查看进程快照信息。

常用选项有:

  • -l:查看当前 Shell 的进程
  • aux:查看所有进程,包括进程使用的 CPU,内存等信息
  • -ef:查看所有进程,包括父进程 PID
  • -u:指定查看某个用户的进程

查看当前 Shell 的进程:

[root@stone ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   6790   6788  0  80   0 - 28984 do_wai pts/1    00:00:00 bash
0 R     0   9380   6790  0  80   0 - 38337 -      pts/1    00:00:00 ps

其中:

  • F:标志位,4 表示根程序,0 表示子程序
  • S:进程状态,S 表示睡眠中(Sleep),R 表示运行中(Running),T 表示停止(Stop),Z 表示僵死(Zombie)
  • UID:用户 ID(User ID)
  • PID:进程 ID(Process ID)
  • PPID:进程父 ID(Parent Process ID)
  • C:CPU 使用率
  • PRI:CPU 优先级(Priority),越小优先级越高,用户无法调整
  • NI:表示 Nice,用于调整 PRI,范围为 -20 ~ 19
  • ADDR:内存位置,一般为 -
  • SZ:使用的内存大小
  • WCHAN:进程是否在运行,如果在运行,则为 -
  • TTY:登录终端
  • TIME:占用 CPU 时间
  • CMD:执行的命令

查看所有进程:

[root@stone ~]# ps aux | head -5
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0 191056  3952 ?        Ss   10:50   0:09 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2  0.0  0.0      0     0 ?        S    10:50   0:00 [kthreadd]
root          4  0.0  0.0      0     0 ?        S<   10:50   0:00 [kworker/0:0H]
root          6  0.0  0.0      0     0 ?        S    10:50   0:01 [ksoftirqd/0]

其中:

  • USER:运行进程的用户名称
  • PID:进程 ID
  • %CPU:进程占用的 CPU 百分比
  • %MEM:进程占用的内存百分比
  • VSZ:分配给进程的虚拟内存大小(Virtual Memory Size),以 KB 为单位
  • RSS:进程使用的物理内存大小(Resident Set Size),以 KB 为单位
  • TTY:登录终端
  • STAT:进程状态
    • S:睡眠中(Sleep)
    • s:父进程
    • <:优先级高的进程
    • R:运行中(Running)
    • T :停止(Stop)
    • Z :僵死(Zombie)
    • D:不可中断,通常处于等待 I/O
    • N:优先级低的进程
    • l:包含多个线程
    • +:进程位于前台
  • START:进程开始时间
  • TIME:占用 CPU 时间
  • COMMAND:执行的命令

查看所有进程:

[root@stone ~]# ps -ef | head -5
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 10:50 ?        00:00:09 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2      0  0 10:50 ?        00:00:00 [kthreadd]
root          4      2  0 10:50 ?        00:00:00 [kworker/0:0H]
root          6      2  0 10:50 ?        00:00:01 [ksoftirqd/0]

其中:

  • UID:用户 ID

  • PID:进程 ID

  • PPID:进程父 ID

  • C:CPU 使用率

  • STIME:进程开始时间

  • TTY:登录终端

  • TIME:占用 CPU 时间

  • CMD:执行的命令

查看某个用户的进程:

[root@stone ~]# ps -u mysql
   PID TTY          TIME CMD
  1414 ?        00:11:14 mysqld

查看线程:

[root@stone ~]# ps -eLf | egrep '(PID|mysqld)' | head -5
UID         PID   PPID    LWP  C NLWP STIME TTY          TIME CMD
mysql      1414      1   1414  0   68 10:50 ?        00:00:02 /usr/sbin/mysqld
mysql      1414      1   1425  0   68 10:50 ?        00:00:01 /usr/sbin/mysqld
mysql      1414      1   1426  0   68 10:50 ?        00:00:01 /usr/sbin/mysqld
mysql      1414      1   1427  0   68 10:50 ?        00:00:01 /usr/sbin/mysqld

[root@stone ~]# ps -T -p `pgrep mysqld`
  PID  SPID TTY          TIME CMD
17478 17478 ?        00:00:21 mysqld
17478 17489 ?        00:20:23 ib_io_ibuf
17478 17490 ?        00:20:32 ib_io_log
17478 17491 ?        00:20:39 ib_io_rd-1
17478 17492 ?        00:20:41 ib_io_rd-2
17478 17493 ?        00:20:44 ib_io_rd-3
17478 17494 ?        00:20:38 ib_io_rd-4
17478 17495 ?        00:41:02 ib_io_wr-1
17478 17496 ?        00:40:49 ib_io_wr-2
17478 17497 ?        00:40:51 ib_io_wr-3
17478 17498 ?        00:40:48 ib_io_wr-4
17478 17499 ?        02:15:02 ib_pg_flush_co
17478 17500 ?        00:03:58 ib_pg_flush-1
17478 17501 ?        00:03:59 ib_pg_flush-2
17478 17502 ?        00:03:59 ib_pg_flush-3
17478 17503 ?        00:57:34 ib_log_checkpt
17478 17504 ?        02:50:27 ib_log_fl_notif
17478 17505 ?        04:29:54 ib_log_flush
17478 17506 ?        02:39:49 ib_log_wr_notif
17478 17507 ?        03:45:43 ib_log_writer
17478 17508 ?        18:04:09 ib_log_files_g
17478 17513 ?        00:12:21 ib_srv_lock_to
17478 17514 ?        00:12:28 ib_srv_err_mon
17478 17515 ?        00:01:07 ib_srv_mon
17478 17516 ?        00:00:00 ib_buf_resize
17478 17517 ?        00:49:07 ib_src_main
17478 17518 ?        00:01:10 ib_dict_stats
17478 17519 ?        00:02:34 ib_fts_opt
17478 17520 ?        00:00:11 xpl_worker-1
17478 17521 ?        00:00:11 xpl_worker-2
17478 17526 ?        00:00:00 ib_buf_dump
17478 17527 ?        03:12:27 ib_clone_gtid
17478 17528 ?        01:27:17 ib_srv_purge
17478 17529 ?        00:25:05 ib_srv_wkr-1
17478 17530 ?        00:18:46 ib_srv_wkr-2
17478 17531 ?        00:16:40 ib_srv_wkr-3
17478 17532 ?        00:00:00 evt_sched
17478 17533 ?        00:00:00 sig_handler
17478 17534 ?        00:00:00 xpl_accept-3
17478 17535 ?        00:14:59 xpl_accept-2
17478 17536 ?        00:00:00 gtid_zip
17478 17540 ?        00:13:55 connection

其中:

  • UID:用户 ID

  • PID:进程 ID

  • PPID:进程父 ID

  • LWP:线程 ID(Light Weight Process)

  • C:CPU 使用率

  • NLWP:线程数据(Number of Light Weight Process)

  • STIME:进程开始时间

  • TTY:登录终端

  • TIME:占用 CPU 时间

  • CMD:执行的命令

查看进程树:

[root@stone ~]# ps axjf | egrep '(PID|httpd)' | grep -v grep
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
     1   1013   1013   1013 ?            -1 Ss       0   0:01 /usr/sbin/httpd -DFOREGROUND
  1013   1058   1013   1013 ?            -1 S       48   0:00  \_ /usr/sbin/httpd -DFOREGROUND
  1013   1059   1013   1013 ?            -1 S       48   0:00  \_ /usr/sbin/httpd -DFOREGROUND
  1013   1060   1013   1013 ?            -1 S       48   0:00  \_ /usr/sbin/httpd -DFOREGROUND
  1013   1062   1013   1013 ?            -1 S       48   0:00  \_ /usr/sbin/httpd -DFOREGROUND
  1013   1063   1013   1013 ?            -1 S       48   0:00  \_ /usr/sbin/httpd -DFOREGROUND

其中:

  • PPID:进程父 ID

  • PID:进程 ID

  • PGID:进程组 ID( Process Group ID)

  • SID:会话 ID(Session ID)

  • TTY:登录终端

  • TPGID:终端上的前台进程组 ID(Foreground Process Group ID),后台运行的进程为 -1

  • STAT:进程状态

  • UID:用户 ID

  • TIME:占用 CPU 时间

  • COMMAND:执行的命令

pstree

使用 pstree 命令以树状显示进程信息。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install psmisc

常用选项有:

  • -p:显示 PID
  • -u:显示 用户名称

查看所有进程,以树状显示:

[root@stone ~]# pstree
systemd─┬─agetty
        ├─auditd───{auditd}
        ├─chronyd
        ├─containerd───10*[{containerd}]
        ├─crond
        ├─dbus-daemon
        ├─dockerd───10*[{dockerd}]
        ├─gssproxy───5*[{gssproxy}]
        ├─httpd───5*[httpd]
        ├─irqbalance
        ├─lvmetad
        ├─mysqld───67*[{mysqld}]
        ├─mysqlrouter───24*[{mysqlrouter}]
        ├─php-fpm───10*[php-fpm]
        ├─polkitd───6*[{polkitd}]
        ├─rpcbind
        ├─rsyslogd───2*[{rsyslogd}]
        ├─sshd─┬─sshd───bash───man───less
        │      ├─sshd───bash───pstree
        │      └─sshd───bash
        ├─systemd-journal
        ├─systemd-logind
        ├─systemd-udevd
        ├─tuned───4*[{tuned}]
        ├─zabbix_agentd───5*[zabbix_agentd]
        └─zabbix_server───37*[zabbix_server]

查看指定父进程,以树状显示,并显示 PID:

[root@stone ~]# pstree 1007 -p
sshd(1007)─┬─sshd(1647)───bash(1649)───man(12010)───less(12020)
           ├─sshd(6788)───bash(6790)───pstree(12773)
           └─sshd(6808)───bash(6810)

查看指定父进程,以树状显示,并显示 PID 和用户名称:

[root@stone ~]# pstree 1013 -p -u
httpd(1013)─┬─httpd(1058,apache)
            ├─httpd(1059,apache)
            ├─httpd(1060,apache)
            ├─httpd(1062,apache)
            └─httpd(1063,apache)

top

使用 top 命令实时查看系统信息,包括内存,CPU以及进程信息。类似于 Windows 的任务管理器。

常用选项有:

  • -d:指定刷新时间间隔,以秒为单位,默认 3 秒
  • -b:以批处理方式运行,将信息重定向到文件
  • -n:一般配合 -b,表示获取 n 次数据后退出
  • -p:指定监控的进程 ID
  • -u:指定用户名称
  • -H:显示线程

查看系统所有进程运行情况:

[root@stone ~]# top
top - 13:31:34 up 2 min,  2 users,  load average: 0.22, 0.19, 0.08
Tasks: 261 total,   1 running, 260 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  1.2 sy,  0.0 ni, 98.1 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  4026164 total,  1668192 free,  1861012 used,   496960 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.  1929864 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                     
  1409 mysql     20   0 2867028 491500  21920 S   4.0 12.2   0:07.80 mysqld                                                      
   769 dbus      20   0   58112   2320   1784 S   0.7  0.1   0:00.09 dbus-daemon                                                 
  1034 zabbix    20   0   78892   2436   1508 S   0.7  0.1   0:00.04 zabbix_agentd                                               
     1 root      20   0  125524   3968   2568 S   0.3  0.1   0:01.36 systemd                                                     
   594 root      20   0       0      0      0 S   0.3  0.0   0:00.07 kworker/1:3                                                 
  1017 root      20   0  372220  41292  15296 S   0.3  1.0   0:01.07 containerd                                                  
  1031 zabbix    20   0   78772   1360    576 S   0.3  0.0   0:00.05 zabbix_agentd                                               
  1032 zabbix    20   0   78892   2412   1484 S   0.3  0.1   0:00.08 zabbix_agentd                                               
  1592 mysqlro+  20   0 1265880  16628   7236 S   0.3  0.4   0:00.34 mysqlrouter
......

其中:

  • 第 1 行与 uptime 命令的输出类似,包括:

    • 13:31:34:表示当前时间
    • up 2 min:表示启动了 2 分钟
    • 2 users:表示有 2 个用户登录到系统
    • load average: 0.22, 0.19, 0.08:表示系统在 1,5,15 分钟内的平均负载
  • 第 2 行显示总进程数量与各状态数量,包括 running,sleeping,stopped,zombie

  • 第 3 行显示各类型负载占 CPU 百分比,包括:

    • us:没有修改优先级的用户进程
    • sy:内核进程
    • ni:修改了优先级的用户进程
    • id:闲置状态
    • wa:等待 I/O 完成
    • hi:硬件中断
    • si:软件中断
    • st:虚拟机
  • 第 4 行显示物理内存使用情况,与 free -k 命令的输出类似,为 /proc/meminfo 的相关内容项,包括:

    • total:总内存,为 /proc/meminfo 中的 MemTotal
    • free:未使用内存,为 /proc/meminfo 中的 MemFree
    • used:已用内存,为 total - free - buffers - cache
    • buff/cachebuff 是内核缓冲(kernel buffers),为 /proc/meminfo 中的 Bufferscache 是页面缓存(page cache)和 slabs,为 /proc/meminfo 中的 CachedSReclaimable
  • 第 5 行显示 SWAP 使用情况,包括:

    • total:总 SWAP,为 /proc/meminfo 中的 SwapTotal
    • free:未使用 SWAP,为 /proc/meminfo 中的 SwapFree
    • used:已用 SWAP,为 total - free
    • avail Mem:可用物理内存,为 /proc/meminfo 中的 MemAvailable
  • 第 7 行及以下为进程信息,包括:

    • PID:进程 ID
    • USER:运行进程的用户名称
    • PR:CPU 优先级(Priority),越小优先级越高,用户无法调整
    • NI:表示 Nice,用于调整 PRI,范围为 -20 ~ 19
    • VIRT:分配给进程的虚拟内存大小(Virtual Memory Size),以 KB 为单位
    • RES:进程使用的物理内存大小(Resident Set Size),以 KB 为单位
    • SHR:进程使用的共享内存大小(Shared Memory Size),以 KB 为单位
    • %CPU:CPU 使用率,如果有多个 CPU,可以使用 H 键切换。默认是按照 CPU 使用率排序,如果不是,使用 P 键按照 CPU 使用率排序
    • %MEM:内存使用率,使用 M 键按照内存排序
    • TIME+:进程启动以来使用的总的 CPU 时间
    • COMMAND:进程名称

查看 MySQL 各个线程运行情况:

[root@stone ~]# top -p 1409 -H
top - 14:35:56 up  1:06,  4 users,  load average: 0.00, 0.05, 0.10
Threads:  68 total,   0 running,  68 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.9 us,  1.5 sy,  0.0 ni, 97.1 id,  0.5 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  4026164 total,  1545580 free,  1911220 used,   569364 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.  1878644 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                      
  1439 mysql     20   0 2869084 527500  22056 S  1.0 13.1   0:27.11 ib_log_files_g                                               
  1435 mysql     20   0 2869084 527500  22056 S  0.7 13.1   0:11.95 ib_log_fl_notif                                              
  1436 mysql     20   0 2869084 527500  22056 S  0.7 13.1   0:20.73 ib_log_flush                                                 
  1438 mysql     20   0 2869084 527500  22056 S  0.7 13.1   0:14.07 ib_log_writer                                                
  1427 mysql     20   0 2869084 527500  22056 S  0.3 13.1   0:04.13 ib_io_wr-2                                                   
  1429 mysql     20   0 2869084 527500  22056 S  0.3 13.1   0:04.34 ib_io_wr-4    
  ......

进入 top 页面后,按下 h 获取帮助信息:

Help for Interactive Commands - procps-ng version 3.3.10
Window 1:Def: Cumulative mode Off.  System: Delay 3.0 secs; Secure mode Off.

  Z,B,E,e   Global: 'Z' colors; 'B' bold; 'E'/'e' summary/task memory scale
  l,t,m     Toggle Summary: 'l' load avg; 't' task/cpu stats; 'm' memory info
  0,1,2,3,I Toggle: '0' zeros; '1/2/3' cpus or numa node views; 'I' Irix mode
  f,F,X     Fields: 'f'/'F' add/remove/order/sort; 'X' increase fixed-width

  L,&,<,> . Locate: 'L'/'&' find/again; Move sort column: '<'/'>' left/right
  R,H,V,J . Toggle: 'R' Sort; 'H' Threads; 'V' Forest view; 'J' Num justify
  c,i,S,j . Toggle: 'c' Cmd name/line; 'i' Idle; 'S' Time; 'j' Str justify
  x,y     . Toggle highlights: 'x' sort field; 'y' running tasks
  z,b     . Toggle: 'z' color/mono; 'b' bold/reverse (only if 'x' or 'y')
  u,U,o,O . Filter by: 'u'/'U' effective/any user; 'o'/'O' other criteria
  n,#,^O  . Set: 'n'/'#' max tasks displayed; Show: Ctrl+'O' other filter(s)
  C,...   . Toggle scroll coordinates msg for: up,down,left,right,home,end

  k,r       Manipulate tasks: 'k' kill; 'r' renice
  d or s    Set update interval
  W,Y       Write configuration file 'W'; Inspect other output 'Y'
  q         Quit
          ( commands shown with '.' require a visible task display window ) 
Press 'h' or '?' for help with Windows,
Type 'q' or <Esc> to continue 

其中:

  • 0:当某一项的值为 0 时,是否显示
  • 1:是否显示所有 CPU 的使用情况
  • K:杀掉指定进程
  • r:改变某个进程优先级
  • q:退出

kill

使用 kill 命令发送信号给进程号。

常用选项有:

  • -l:列出信号编码和名称

查看信号编码和名称:

[root@stone ~]# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2

其中:

  • 1) SIGHUP:通知进程重新加载配置文件
  • 9) SIGKILL:强制终止进程
  • 15) SIGTERM:结束进程,默认值。会等待正在进行的工作完成后才结束,如果卡死了,则无法结束

在一个 Session 中启动一个命令:

[root@stone ~]# tail -10f /var/log/messages

在另一个 Session 找到该进程号,强制结束该进程:

[root@stone ~]# pidof tail
5999
[root@stone ~]# kill -9 5999

或者:

[root@stone ~]# kill -9 `pidof tail`

或者:

[root@stone ~]# kill -9 `ps -ef | grep tail | grep -v grep | awk '{print $2}'`

killall

使用 killall 命令发送信号给进程名称。

常用选项有:

  • -u:发送信号给某个用户的所有进程
  • -i:交互操作,需用户确认
  • -w:等待进程结束后再返回
  • -o:发送信号给运行超过指定时间(Older)的进程,单位可以是 s(seconds),m(minutes),h(hours),d(days),w(weeks),M(Months),y(years)
  • -y:发送信号给运行小于指定时间(Younger)的进程,单位可以是 s(seconds),m(minutes),h(hours),d(days),w(weeks),M(Months),y(years)

结束某个进程:

[root@stone ~]# killall tail

强制结束某个用户的所有进程:

[root@stone ~]# ps -u stone
   PID TTY          TIME CMD
  6676 pts/0    00:00:00 bash
  6741 pts/0    00:00:00 tail
[root@stone ~]# killall -9 -u stone
[root@stone ~]# ps -u stone
   PID TTY          TIME CMD
[root@stone ~]# 

nice

使用 nice 命令调整命令的优先级。

常用选项有:

  • -n:指定调整值,默认为 10,调整后范围为 -20 ~ 19
[root@stone ~]# nice -n -5 tail -1f /var/log/messages &
[1] 7161

[root@stone ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   1534   1532  0  80   0 - 29047 do_wai pts/0    00:00:00 bash
4 S     0   7161   1534  0  75  -5 - 27023 wait_w pts/0    00:00:00 tail
0 R     0   7162   1534  0  80   0 - 38337 -      pts/0    00:00:00 ps

[root@stone ~]# kill -9 7161

[root@stone ~]# nice tail -1f /var/log/messages &
[1] 7244

[root@stone ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   1534   1532  0  80   0 - 29047 do_wai pts/0    00:00:00 bash
0 S     0   7244   1534  0  90  10 - 27023 wait_w pts/0    00:00:00 tail
0 R     0   7248   1534  0  80   0 - 38337 -      pts/0    00:00:00 ps

renice

使用 renice 命令调整正在运行命令的优先级。

[root@stone ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   1534   1532  0  80   0 - 29047 do_wai pts/0    00:00:00 bash
0 S     0   7244   1534  0  90  10 - 27023 wait_w pts/0    00:00:00 tail
0 R     0   7248   1534  0  80   0 - 38337 -      pts/0    00:00:00 ps
[root@stone ~]# renice -5 7244
7244 (process ID) old priority 10, new priority -5
[root@stone ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   1534   1532  0  80   0 - 29047 do_wai pts/0    00:00:00 bash
0 S     0   7244   1534  0  75  -5 - 27023 wait_w pts/0    00:00:00 tail
0 R     0   7269   1534  0  80   0 - 38337 -      pts/0    00:00:00 ps

fuser

使用 fuser 命令查找使用文件的进程。

常用选项有:

  • -u:显示进程的用户名称

  • -v:显示进程的用户名称(USER),进程 ID(PID),访问类型(ACCESS)及命令(COMMAND),其中访问类型包括:

    • c:当前目录
    • e:正在运行的可执行文件
    • f:打开的文件
    • F:打开文件进行写入
    • r:根目录
    • m:映射文件或共享库
  • -m:列出访问该文件所在文件系统的文件的所有进程,当使用 umount 命令卸载某个文件系统时,如果提示 target is busy,使用该选项可以方便的找到与该文件系统相关的进程

  • -k:默认发送 SIGKILL 信号给找到的进程

  • -i:与 -k 选项配合,需要用户进行确认

[root@stone ~]# fuser /var/log/messages
/var/log/messages:    1014
[root@stone ~]# fuser -u /var/log/messages
/var/log/messages:    1014(root)
[root@stone ~]# fuser -vu /var/log/messages
                     USER        PID ACCESS COMMAND
/var/log/messages:   root       1014 F.... (root)rsyslogd

pidof

使用 pidof 命令列出进程的 PID。

[root@stone ~]# pidof rsyslogd
1014

lsof

使用 lsoflist open files)命令列出由进程打开的文件。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install lsof

常用选项有:

  • -p:查看某个进程 ID 打开的文件

  • -u:查看某个用户名称打开的文件

  • -i:查看与某个网络地址匹配的文件,网络地址格式为: [46][protocol][@hostname|hostaddr][:service|port],其中:

    • [46]:IPv4 或者 IPv6
    • [protocol]:协议名称,TCP,UDP等
    • [@hostname|hostaddr]:主机名称或者地址
    • [:service|port]:服务名称(/etc/services)或者端口
  • +d:列出指定目录下打开的文件

  • +D:列出指定目录及其子目录下打开的文件

  • -t:只列出进程 ID

执行以下命令:

[root@stone ~]# tail -1f /var/log/messages
Jul 27 14:19:26 stone systemd-logind: New session 43 of user root.

在另外的 Shell 环境查看进程打开的文件:

[root@stone ~]# lsof -p `pidof tail`
COMMAND   PID USER   FD      TYPE DEVICE  SIZE/OFF      NODE NAME
tail    21070 root  cwd       DIR  253,0      4096  67146817 /root
tail    21070 root  rtd       DIR  253,0       256        64 /
tail    21070 root  txt       REG  253,0     66824 100873306 /usr/bin/tail
tail    21070 root  mem       REG  253,0 106172832 100882464 /usr/lib/locale/locale-archive
tail    21070 root  mem       REG  253,0   2156240     12121 /usr/lib64/libc-2.17.so
tail    21070 root  mem       REG  253,0    163312     12114 /usr/lib64/ld-2.17.so
tail    21070 root    0u      CHR  136,3       0t0         6 /dev/pts/3
tail    21070 root    1u      CHR  136,3       0t0         6 /dev/pts/3
tail    21070 root    2u      CHR  136,3       0t0         6 /dev/pts/3
tail    21070 root    3r      REG  253,0    573448  34350300 /var/log/messages
tail    21070 root    4r  a_inode   0,10         0      7512 inotify

其中:

  • FD:文件描述符(File Descriptor),包括:
    • cwd:执行命令的当前目录(current working directory)
    • rtd:根目录(root directory)
    • txt:程序文件(program text
    • mem:内存映射文件(memory-mapped file)
    • 0u0 表示标准输入,u 表示可读可写
    • 1u1 表示标准输出,u 表示可读可写
    • 2u2 表示标准错误,u 表示可读可写
  • TYPE:文件类型,包括:
    • DIR:目录(directory)
    • REG:普通文件(regular file)
    • CHR:字符特殊文件(character special file),或者字符设备(character devices)
  • DEVICE:设备编号,来自于 /proc/devices
  • SIZE/OFF:文件大小
  • NODE:节点编号(Inode)
  • NAME:文件名称

还可以查看打开文件的进程:

[root@stone ~]# lsof /var/log/messages
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
rsyslogd  1014 root    7w   REG  253,0   573899 34350300 /var/log/messages
tail     21070 root    3r   REG  253,0   573899 34350300 /var/log/messages

[root@stone ~]# lsof -t /var/log/messages
1014
21070

查看某个用户的进程:

[root@stone ~]# lsof -t -u stone
24307

查看在 22 端口上打开的文件:

[root@stone ~]# lsof -i :22
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd     1013 root    3u  IPv4  27295      0t0  TCP *:ssh (LISTEN)
sshd     1013 root    4u  IPv6  27297      0t0  TCP *:ssh (LISTEN)
sshd     1589 root    3u  IPv4  29149      0t0  TCP stone:ssh->192.168.44.1:49226 (ESTABLISHED)
sshd     7702 root    3u  IPv4 120009      0t0  TCP stone:ssh->192.168.44.1:64953 (ESTABLISHED)
sshd    10885 root    3u  IPv4 126210      0t0  TCP stone:ssh->192.168.44.1:51178 (ESTABLISHED)
sshd    21039 root    3u  IPv4 147992      0t0  TCP stone:ssh->192.168.44.1:61072 (ESTABLISHED)
sshd    21596 root    3u  IPv4 149581      0t0  TCP stone:ssh->192.168.44.1:61198 (ESTABLISHED)

查看指定目录下打开的文件及对应进程:

[root@stone ~]# lsof +d /root/
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
bash     1591 root  cwd    DIR  253,0     4096 67146817 /root

如果文件被误删除了,只要还有进程正在访问该文件,则可以使用 lsof 命令找到被误删除的文件并进行恢复,例如有以下文件:

[root@stone ~]# cp /var/log/messages messages
[root@stone ~]# tail -1f messages 
Jul 27 15:20:01 stone systemd: Started Session 52 of user root.

在其他会话删除该文件:

[root@stone ~]# rm -fr messages 

找到打开该文件的进程:

[root@stone ~]# lsof | grep message | grep delete
tail      25366         root    3r      REG              253,0    574078   67153793 /root/messages (deleted)

可以看到进程 25366 打开了删除的文件,其文件描述符为 3r,最后面的 (deleted) 表示被删除,此时可以将 /proc/25366/fd/3 复制到原文件即可:

[root@stone ~]# cp /proc/25366/fd/3 messages

工作管理

在实际工作中,往往会有如下需求:

  • 在同一个 Shell 中,同时执行多个命令。
  • 断开 Shell 后,命令继续运行,不会中断。

此时就需要对执行的命令进行工作(Job)管理。

&

使用 & 将命令放到 Shell 后台执行。

[root@stone ~]# find / -name mysql.sock > /tmp/find.txt 2>&1 &
[1] 3119

其中:

  • [1]:工作编号
  • 3119:进程号

待命令在后台执行完成后,会输出如下信息:

[root@stone ~]# 
[1]+  Done                    find / -name mysql.sock > /tmp/find.txt 2>&1

表示编号为 1 的工作已完成。

Ctrl + z

使用 Ctrl + z 组合按键可以将正在执行的命令放入 Shell 后台并暂停执行。

例如在执行 tail -f 命令时可以按下 Ctrl + z 将其放入 Shell 后台并暂停执行:

[root@stone ~]# tail -1f /var/log/messages
Jul 27 09:20:01 stone systemd: Started Session 6 of user root.
^Z
[1]+  Stopped                 tail -1f /var/log/messages

其中

  • [1]:工作编号
  • Stopped:暂停执行

jobs

使用 jobs 命令查看 Shell 后台的工作。

常用选项有:

  • -l:列出额外的进程 ID
  • -r:仅列出运行的工作
  • -s:仅列出暂停的工作
[root@stone ~]# jobs -l
[1]+  2953 Stopped                 tail -1f /var/log/messages
[root@stone ~]# find / -mmin -5 > /tmp/find.txt 2>&1 &
[2] 1994
[root@stone ~]# jobs
[1]+  Stopped                 tail -1f /var/log/messages
[2]-  Running                 find / -mmin -5 > /tmp/find.txt 2>&1 &

fg

使用 fg 命令将 Shell 后台工作放到前台运行。

[root@stone ~]# fg %1
tail -1f /var/log/messages

其中:

  • 1:表示工作编号,% 可加可不加

bg

使用 bg 命令运行在 Shell 后台暂停的工作。

[root@stone ~]# fg 1
tail -1f /var/log/messages
^Z
[1]+  Stopped                 tail -1f /var/log/messages
[root@stone ~]# jobs -l
[1]+  3173 Stopped                 tail -1f /var/log/messages
[root@stone ~]# bg 1
[1]+ tail -1f /var/log/messages &
[root@stone ~]# jobs
[1]+  Running                 tail -1f /var/log/messages &

此时要停止该工作,既可以使用 fg 命令将其放到前台,然后使用 Ctrl + C 结束,也可以使用 kill 命令。使用 kill 命令时,既可以指定进程 ID,也可以使用百分号加上工作编号。

[root@stone ~]# kill -9 %1
[root@stone ~]# jobs -l
[1]+  3173 Killed                  tail -1f /var/log/messages

nohup

使用 nohupno hangup)配合 & 将命令放到系统后台执行。

如果只是使用 & 将命令放入到 Shell 后台执行,那么在离开 Shell 环境后,命令会被中断,要保持命令继续执行,需要使用 nohup

使用 nohupsleep 300(睡眠 300 秒)命令放到系统后台执行,可以指定输出重定向,如果不指定,会将输出写入到当前目录的 nohup.out 文件中:

[root@stone ~]# nohup sleep 300 > /tmp/sleep.log 2>&1 &
[1] 7418
[root@stone ~]# logout

使用 logout 命令离开 Shell 环境后,再重新登录到系统查看:

[root@stone ~]# ps -ef | grep sleep | grep -v grep
root       7418      1  0 10:37 ?        00:00:00 sleep 300

服务

与 Windows 类似,Linux 也有很多的服务,本节介绍如何管理 Linux 的服务。

简介

什么是服务呢?简而言之,服务就是系统为提供某些功能而在后台运行的一系列程序。从 CentOS 7 开始,systemd 取代了 SysV 作为默认的服务管理程序。相比 SysVsystemd 相当复杂,有非常多的概念和命令,这里只介绍最常用的概念和命令,更详细的内容请参考官方文档open in new window

下图为 systemd 的架构图,看看就好。

systemd的结构

systemd 相关的目录和文件有很多,重点关注以下两个目录及其里面的文件:

  • /etc/systemd/system:开机时会读取该目录下的配置文件,实际为软链接,指向 /usr/lib/systemd/system/ 目录下的文件。
[root@stone ~]# ll /etc/systemd/system
total 4
drwxr-xr-x. 2 root root   57 Jun 22 20:38 basic.target.wants
lrwxrwxrwx. 1 root root   41 Jun 22 20:37 dbus-org.fedoraproject.FirewallD1.service -> /usr/lib/systemd/system/firewalld.service
lrwxrwxrwx. 1 root root   57 Jun 22 20:37 dbus-org.freedesktop.nm-dispatcher.service -> /usr/lib/systemd/system/NetworkManager-dispatcher.service
lrwxrwxrwx. 1 root root   37 Jun 22 20:39 default.target -> /lib/systemd/system/multi-user.target
drwxr-xr-x. 2 root root   87 Jun 22 20:37 default.target.wants
drwxr-xr-x. 2 root root   32 Jun 22 20:37 getty.target.wants
drwxr-xr-x. 2 root root   35 Jun 22 20:37 local-fs.target.wants
drwxr-xr-x. 2 root root 4096 Jun 22 20:38 multi-user.target.wants
drwxr-xr-x. 2 root root   48 Jun 22 20:37 network-online.target.wants
drwxr-xr-x. 2 root root   29 Jun 22 20:37 sockets.target.wants
drwxr-xr-x. 2 root root  254 Jun 22 20:37 sysinit.target.wants
drwxr-xr-x. 2 root root   44 Jun 22 20:37 system-update.target.wants
[root@stone ~]# ll /etc/systemd/system/multi-user.target.wants/
total 0
lrwxrwxrwx. 1 root root 38 Jun 22 20:37 auditd.service -> /usr/lib/systemd/system/auditd.service
lrwxrwxrwx. 1 root root 37 Jun 22 20:37 crond.service -> /usr/lib/systemd/system/crond.service
lrwxrwxrwx. 1 root root 41 Jun 22 20:37 firewalld.service -> /usr/lib/systemd/system/firewalld.service
lrwxrwxrwx. 1 root root 42 Jun 22 20:38 irqbalance.service -> /usr/lib/systemd/system/irqbalance.service
lrwxrwxrwx. 1 root root 37 Jun 22 20:37 kdump.service -> /usr/lib/systemd/system/kdump.service
lrwxrwxrwx. 1 root root 46 Jun 22 20:37 NetworkManager.service -> /usr/lib/systemd/system/NetworkManager.service
lrwxrwxrwx. 1 root root 39 Jun 22 20:37 postfix.service -> /usr/lib/systemd/system/postfix.service
lrwxrwxrwx. 1 root root 40 Jun 22 20:37 remote-fs.target -> /usr/lib/systemd/system/remote-fs.target
lrwxrwxrwx. 1 root root 46 Jun 22 20:37 rhel-configure.service -> /usr/lib/systemd/system/rhel-configure.service
lrwxrwxrwx. 1 root root 39 Jun 22 20:38 rsyslog.service -> /usr/lib/systemd/system/rsyslog.service
lrwxrwxrwx. 1 root root 36 Jun 22 20:37 sshd.service -> /usr/lib/systemd/system/sshd.service
lrwxrwxrwx. 1 root root 37 Jun 22 20:37 tuned.service -> /usr/lib/systemd/system/tuned.service
  • /usr/lib/systemd/system:存放各种类型的服务配置文件。
[root@stone ~]# ll /usr/lib/systemd/system
total 800
-rw-r--r--. 1 root root 1384 Aug  8  2019 auditd.service
lrwxrwxrwx. 1 root root   14 Jun 22 20:37 autovt@.service -> getty@.service
-rw-r--r--. 1 root root  517 Oct  2  2020 basic.target
drwxr-xr-x. 2 root root   67 Jun 22 20:37 basic.target.wants
-r--r--r--. 1 root root  429 Oct  1  2020 blk-availability.service
-rw-r--r--. 1 root root  379 Oct  2  2020 bluetooth.target
-rw-r--r--. 1 root root  160 May 22  2020 brandbot.path
-rw-r--r--. 1 root root  116 May 22  2020 brandbot.service
-rw-r--r--. 1 root root  787 Oct  2  2020 console-getty.service
-rw-r--r--. 1 root root  749 Oct  2  2020 console-shell.service
-rw-r--r--. 1 root root  808 Oct  2  2020 container-getty@.service
-rw-r--r--. 1 root root  294 Oct 20  2020 cpupower.service
-rw-r--r--. 1 root root  318 Aug  9  2019 crond.service
......

Unit

Unit 是管理服务的基本单元,在 /usr/lib/systemd/system 目录下的文件就是各个 Unit 的配置文件。

systemd 中可用的 Unit 类型有 11 种,需要重点关注以下 2 种类型:

  • Service:用于启动和控制守护进程(daemons),以 .service 为文件扩展名,最常见的 Unit。
  • Target:对 Unit 进行分组,一个或多个其它类型 Unit 的集合,以 .target 为文件扩展名。

Service

对于 Service 类型,来看看其配置文件:

[root@stone ~]# cat /usr/lib/systemd/system/sshd.service 
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

其中:

  • [Unit]:定义 Unit 的基本信息,与 Unit 的类型无关,包括:

    • Description:简要的描述信息。
    • Documentation:参考文档。
    • Before:指定其它 Unit 对该 Unit 的依赖性,其它 Unit 需在该 Unit 启动后才能启动。
    • After:指定该 Unit 对其它 Unit 的依赖性,该 Unit 需在其它 Unit 启动后才能启动。
    • Wants:配置对其它 Unit 的弱依赖关系,即使指定 Unit 启动失败也不影响该 Unit 的启动,也不影响启动顺序。
    • Requires:与 Wants 类似,但配置对其它 Unit 的强依赖关系,指定 Unit 启动失败会影响该 Unit 的启动。
    • Conflicts:指定冲突的 Unit。
  • [Service]:指定服务及其相关进程的信息,只有 Service 类型的 Unit 才有此项,包括:

    • Type:配置进程启动类型,包括:
      • simple:默认值,执行 ExecStart 指定的命令,启动主进程。
      • exec:与 simple 类似,不同之处在于,只有在该服务的主服务进程执行完成之后,systemd 才会认为该服务启动完成。 其他后继单元必须一直阻塞到这个时间点之后才能继续启动。
      • forkingExecStart 将以 fork() 方式启动,此时父进程将会退出,子进程将成为主进程。
      • oneshot:与 simple 类似,不同之处在于,只有在该服务的主服务进程退出之后,systemd 才会认为该服务启动完成,才会开始启动后续 Unit。 此种类型的服务通常需要设置 RemainAfterExit 选项。当 TypeExecStart 都没有设置时,oneshot 就是默认值。
      • dbus:与 simple 类似,但会等待 D-Bus 信号后启动。
      • notify:与 exec 类似,启动结束后会发出通知信号,然后再启动其他服务。
      • idle:与 simple 类似,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合。
    • EnvironmentFile:指定当前服务的环境变量文件。
    • ExecStart:指定启动进程时执行的命令。
    • ExecReload:指定当该服务被要求重新加载配置时所执行的命令。
    • ExecStop:指定停止服务时执行的命令。
    • KillMode:如何停止服务,包括:
      • control-group:默认值,当前控制组里面的所有子进程,都会被终止。
      • mixed:发送 SIGTERM 给主进程,发送 SIGKILL 给其他进程。
      • process:仅终止主进程。
      • none:仅停止服务,不终止进程。
    • Restart:指定重启策略,包括 no(默认值),on-successon-failureon-abnormalon-watchdogon-abortalways,具体如下:
    Restart settings/Exit causesnoalwayson-successon-failureon-abnormalon-aborton-watchdog
    Clean exit code or signalXX
    Unclean exit codeXX
    Unclean signalXXXX
    TimeoutXXX
    WatchdogXXXX
    • RestartSec:重启服务前等待的时间,默认为 100ms。
  • [Install]:说明此 Unit 的安装信息,包括:

    • WantedBy:指定一个或多个 Target 类型 Unit,说明此 Unit 属于哪个 Target。

Target

前面提到 Target 就是一组 Unit,包含许多相关的 Unit 。启动某个 Target 时,systemd 就会启动里面所有的 Unit。

  • 如果 Target 只包含一个 Unit,则只有一个对应的配置文件,没有对应的目录。例如名称为 hibernate.target 的 Target 只包含一个名称 systemd-hibernate.service 的 Unit,该 Unit 位于 /usr/lib/systemd/system/ 目录下:
[root@stone ~]# ll /usr/lib/systemd/system/hibernate*
-rw-r--r--. 1 root root 447 Oct  2  2020 /usr/lib/systemd/system/hibernate.target
  • 如果 Target 包含多个 Unit,除了配置文件外,还有对应的目录,存放该 Target 包含的 Unit 的软链接。例如名称为 multi-user.target 的 Target 包含了多个 Unit,则会有一个名称为 multi-user.target.wants 的目录存放该 Target 包含的 Unit 的软链接:
[root@stone ~]# ll /usr/lib/systemd/system/multi-user.target*
-rw-r--r--. 1 root root 492 Oct  2  2020 /usr/lib/systemd/system/multi-user.target

/usr/lib/systemd/system/multi-user.target.wants:
total 0
lrwxrwxrwx. 1 root root 15 Jun 22 20:37 dbus.service -> ../dbus.service
lrwxrwxrwx. 1 root root 15 Jun 22 20:37 getty.target -> ../getty.target
lrwxrwxrwx. 1 root root 24 Jun 22 20:37 plymouth-quit.service -> ../plymouth-quit.service
lrwxrwxrwx. 1 root root 29 Jun 22 20:37 plymouth-quit-wait.service -> ../plymouth-quit-wait.service
lrwxrwxrwx. 1 root root 33 Jun 22 20:37 systemd-ask-password-wall.path -> ../systemd-ask-password-wall.path
lrwxrwxrwx. 1 root root 25 Jun 22 20:37 systemd-logind.service -> ../systemd-logind.service
lrwxrwxrwx. 1 root root 39 Jun 22 20:37 systemd-update-utmp-runlevel.service -> ../systemd-update-utmp-runlevel.service
lrwxrwxrwx. 1 root root 32 Jun 22 20:37 systemd-user-sessions.service -> ../systemd-user-sessions.service

将系统在不同的状态时需要运行的 Unit 分组为不同的 Target,systemd 就可以使用不同的 Target 将系统启动或者切换到对应的状态,类似于 CentOS 7 之前的 RunLevel。RunLevel 与 Target 的对应关系如下:

[root@stone ~]# ll /usr/lib/systemd/system/runlevel*.target
lrwxrwxrwx. 1 root root 15 Jun 22 20:37 /usr/lib/systemd/system/runlevel0.target -> poweroff.target
lrwxrwxrwx. 1 root root 13 Jun 22 20:37 /usr/lib/systemd/system/runlevel1.target -> rescue.target
lrwxrwxrwx. 1 root root 17 Jun 22 20:37 /usr/lib/systemd/system/runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Jun 22 20:37 /usr/lib/systemd/system/runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Jun 22 20:37 /usr/lib/systemd/system/runlevel4.target -> multi-user.target
lrwxrwxrwx. 1 root root 16 Jun 22 20:37 /usr/lib/systemd/system/runlevel5.target -> graphical.target
lrwxrwxrwx. 1 root root 13 Jun 22 20:37 /usr/lib/systemd/system/runlevel6.target -> reboot.target
RunlevelTarget说明
0poweroff.target关闭系统
1rescue.target维护模式
2,3,4multi-user.target多用户,文字界面,默认 Target
5graphical.target多用户,图形界面
6reboot.target重启系统

不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是某些 Target 是可以同时启动的。例如上面的 multi-user.targetgraphical.target 是可以同时启动的,通过启动或关闭这两个 Target 之间不同的 Unit,可以实现文字界面和图形界面的快速切换。

默认的启动 Target 由 /etc/systemd/system/default.target 文件指定,一般软连接到 multi-user.target 或者 graphical.target

[root@stone ~]# ll /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 37 Jun 22 20:39 /etc/systemd/system/default.target -> /lib/systemd/system/multi-user.target

对于 Target 类型,来看看其配置文件:

[root@stone ~]# cat /usr/lib/systemd/system/multi-user.target
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target

其中各项含义与 Service 配置文件一样。

命令

systemd 包含许多命令来管理 Unit 和系统,这里介绍最常用的。

systemctl

使用 systemctl 命令管理 Unit。

常用选项有:

  • -t:指定 Unit 类型
  • -a:显示所有 Unit

常用 Unit 子命令有:

  • list-units:列出加载的 Unit
  • start:启动 Unit
  • stop:停止 Unit
  • reload:重载 Unit
  • restart:重启 Unit
  • status:查看 Unit 状态
  • is-active:检查 Unit 是否 Active
  • is-failed:检查 Unit 是否 Failed
  • isolate:在不同的 Target 之间切换
  • kill:发送信号给 Unit
  • list-dependencies:列出 Unit 依赖
  • cat:查看 Unit 配置文件

常用 Unit 文件子命令:

  • list-unit-files:列出安装的 Unit 文件
  • enable:配置 Unit 开机启动
  • disable:配置 Unit 开机不启动
  • is-enabled:查看是否开机启动
  • edit:编辑 Unit 配置文件
  • get-default:获取默认 Target
  • set-default:设置默认 Target

常用管理器生命周期命令:

  • daemon-reload:重载所有修改过的配置文件

常用系统命令:

  • is-system-running:检查系统是否完全运行
  • default:进入系统默认模式
  • rescue:进入系统拯救模式
  • emergency:进入系统紧急模式
  • halt:关闭和停止系统
  • poweroff:关闭系统并断电
  • reboot:重启
  • suspend:挂起系统
  • hibernate:休眠

虽然 systemctl 有这么多的子命令,但用得最多的还是 Unit 管理的这几个子命令,具体如下:

任务旧命令(CentOS 7)新命令(CentOS 7)
配置开机启动chkconfig --level 3 crond onsystemctl enable crond.service
配置开机不启动chkconfig --level 3 crond offsystemctl disable crond.service
查看 Unit 状态service crond statussystemctl status crond.service (服务详细信息)
systemctl is-active crond.service (仅显示是否 Active)
显示所有已启动 Unitchkconfig --listsystemctl list-units --type=service
启动 Unitservice crond startsystemctl start crond.service
停止 Unitservice crond stopsystemctl stop crond.service
重启 Unitservice crond restartsystemctl restart crond.service

查看 Unit 状态:

[root@stone ~]# systemctl status crond.service
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2023-07-29 09:44:58 CST; 6h ago
 Main PID: 771 (crond)
   CGroup: /system.slice/crond.service
           └─771 /usr/sbin/crond -n

Jul 29 09:44:58 stone systemd[1]: Started Command Scheduler.
Jul 29 09:44:58 stone crond[771]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 24% if used.)
Jul 29 09:44:58 stone crond[771]: (CRON) INFO (running with inotify support)

其中:

第 2 行的 /usr/lib/systemd/system/crond.service; enabled 表示配置文件及开机启动

第 3 行的 Active 表示运行状态,包括:

  • active (running):服务正在运行
  • inactive (dead):服务已经停止

停止 Unit:

[root@stone ~]# systemctl stop crond.service
[root@stone ~]# systemctl status crond.service
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Sat 2023-07-29 16:35:37 CST; 8s ago
  Process: 771 ExecStart=/usr/sbin/crond -n $CRONDARGS (code=exited, status=0/SUCCESS)
 Main PID: 771 (code=exited, status=0/SUCCESS)

Jul 29 09:44:58 stone systemd[1]: Started Command Scheduler.
Jul 29 09:44:58 stone crond[771]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 24% if used.)
Jul 29 09:44:58 stone crond[771]: (CRON) INFO (running with inotify support)
Jul 29 16:35:37 stone systemd[1]: Stopping Command Scheduler...
Jul 29 16:35:37 stone systemd[1]: Stopped Command Scheduler.

开机启动设置:

[root@stone ~]# systemctl is-enabled crond.service
enabled
[root@stone ~]# systemctl disable crond.service
Removed symlink /etc/systemd/system/multi-user.target.wants/crond.service.
[root@stone ~]# systemctl is-enabled crond.service
disabled
[root@stone ~]# systemctl enable crond.service      
Created symlink from /etc/systemd/system/multi-user.target.wants/crond.service to /usr/lib/systemd/system/crond.service.

可以看到,配置开机启动就是创建 /etc/systemd/system/multi-user.target.wants/crond.service/usr/lib/systemd/system/crond.service 的软链接,配置开机不启动就是删除该软链接。

启动 Unit 或者重启 Unit:

[root@stone ~]# systemctl start crond.service
[root@stone ~]# systemctl restart crond.service

查看配置文件:

[root@stone ~]# systemctl cat crond.service
# /usr/lib/systemd/system/crond.service
[Unit]
Description=Command Scheduler
After=auditd.service systemd-user-sessions.service time-sync.target

[Service]
EnvironmentFile=/etc/sysconfig/crond
ExecStart=/usr/sbin/crond -n $CRONDARGS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target

修改配置文件后,需要重载配置文件才会生效:

[root@stone ~]# systemctl daemon-reload

journalctl

使用 journalctl 命令查看由 systemd 产生的日志。

常用选项有:

  • -u:查看指定 Unit 的日志
  • -f:实时查看最新日志
[root@stone ~]# journalctl -u crond.service | tail -5
Jul 29 16:41:14 stone systemd[1]: Stopped Command Scheduler.
Jul 29 16:41:14 stone systemd[1]: Started Command Scheduler.
Jul 29 16:41:14 stone crond[2865]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 58% if used.)
Jul 29 16:41:14 stone crond[2865]: (CRON) INFO (running with inotify support)
Jul 29 16:41:14 stone crond[2865]: (CRON) INFO (@reboot jobs will be run at computer's startup.)

hostnamectl

使用 hostnamectl 命令管理主机名。

常用子命令有:

  • set-hostname:设置主机名

查看主机名:

[root@stone ~]# hostnamectl 
   Static hostname: stone
Transient hostname: status
         Icon name: computer-vm
           Chassis: vm
        Machine ID: d8f49d804904484184e0ccd2511cd4a4
           Boot ID: 6a0c999d9ea443208c845b4b4b1aa5a8
    Virtualization: vmware
  Operating System: CentOS Linux 7 (Core)
       CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 3.10.0-1160.el7.x86_64
      Architecture: x86-64
[root@stone ~]# cat /etc/hostname 
stone

调整主机名:

[root@stone ~]# hostnamectl set-hostname stone1
[root@stone ~]# hostnamectl 
   Static hostname: stone1
         Icon name: computer-vm
           Chassis: vm
        Machine ID: d8f49d804904484184e0ccd2511cd4a4
           Boot ID: 6a0c999d9ea443208c845b4b4b1aa5a8
    Virtualization: vmware
  Operating System: CentOS Linux 7 (Core)
       CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 3.10.0-1160.el7.x86_64
      Architecture: x86-64
[root@stone ~]# cat /etc/hostname 
stone1

localectl

使用 localectl 命令管理本地化设置。

常用子命令有:

  • set-locale:设置本地化参数
[root@stone ~]# localectl 
   System Locale: LANG=en_US.UTF-8
       VC Keymap: us
      X11 Layout: us

timedatectl

使用 timedatectl 命令管理系统时间和日期。

常用子命令有:

  • set-time:设置系统时间
  • set-timezone:设置系统时区
[root@stone ~]# timedatectl 
      Local time: Sat 2023-07-29 17:57:42 CST
  Universal time: Sat 2023-07-29 09:57:42 UTC
        RTC time: Sat 2023-07-29 12:32:15
       Time zone: Asia/Shanghai (CST, +0800)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

[root@stone ~]# timedatectl set-time 20:34:20

[root@stone ~]# timedatectl 
      Local time: Sat 2023-07-29 20:34:22 CST
  Universal time: Sat 2023-07-29 12:34:22 UTC
        RTC time: Sat 2023-07-29 12:34:23
       Time zone: Asia/Shanghai (CST, +0800)
     NTP enabled: n/a
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

loginctl

使用 loginctl 命令管理登录会话和用户。

常用子命令有:

  • list-sessions:列出 Session
  • terminate-session:终止 Session
  • kill-session:发生信号给 Session 进程
  • list-users:列出用户
  • terminate-user:终止用户的所有 Session
  • kill-user:发送信号给用户的进程
[root@stone ~]# loginctl list-sessions
   SESSION        UID USER             SEAT            
         1          0 root                             
         2          0 root                             

2 sessions listed.
[root@stone ~]# loginctl list-users
       UID USER            
         0 root            

1 users listed.

任务

与 Windows 类似,Linux 也可以配置计划任务,本节介绍如何管理 Linux 的计划任务。

可以将计划任务分为两类:

  • 单次执行:使用 atd 服务,在指定时间执行任务一次。
  • 循环执行:使用 crond 服务,按照配置循环执行任务。

单次执行

在实际工作中,有时需要在未来的某个时间点执行某个命令或者脚本,可以使用 atd 服务的相关命令进行配置。

如果系统没有该服务,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install at

安装后启动 atd 服务:

[root@stone ~]# systemctl start atd
[root@stone ~]# systemctl status atd
● atd.service - Job spooling tools
   Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2023-07-31 09:06:18 CST; 13s ago
 Main PID: 1692 (atd)
    Tasks: 1
   Memory: 216.0K
   CGroup: /system.slice/atd.service
           └─1692 /usr/sbin/atd -f

Jul 31 09:06:18 stone systemd[1]: Started Job spooling tools.

at

使用 at 命令创建单次执行任务。

常用选项有:

  • -l:列出还没有执行的单次任务,等效于命令 atq
  • -r:删除单次任务,等效于命令 atrm
  • -c:查看任务内容,实际上查看的是 /var/spool/at/ 目录下的文件

常用时间格式:

  • HH:MM YY-MM-DD:未来的某个时间点
  • now + N [minutes][hours][days][weeks]:在现在时间的 N 分钟,小时,天或周之后

使用交互模式配置单次任务:

[root@stone ~]# at 09:55 2023-07-31
at> free -m > /root/free.log
at> <EOT>
job 2 at Mon Jul 31 09:55:00 2023

[root@stone ~]# at -l
2       Mon Jul 31 09:55:00 2023 a root

[root@stone ~]# at -c 2
......
free -m > /root/free.log
......

其中:

  • 09:55 2023-07-31:为指定的时间点
  • free -m > /root/free.log:为任务内容
  • <EOT>:为按下组合键 Ctrl + d 后退出交互模式

使用标准输入配置单次任务:

[root@stone ~]# echo "df -h > df.log" | at now +10 minutes
job 3 at Mon Jul 31 10:00:00 2023

[root@stone ~]# at -l
2       Mon Jul 31 09:55:00 2023 a root
3       Mon Jul 31 10:00:00 2023 a root

[root@stone ~]# at -c 3
......
df -h > df.log
......

删除任务:

[root@stone ~]# at -l
3       Mon Jul 31 10:00:00 2023 a root
[root@stone ~]# at -r 3
[root@stone ~]# at -l
[root@stone ~]# 

循环执行

在实际工作中,经常需要每天或者每周循环执行某个命令或者脚本,可以使用 crond 服务的相关命令进行配置。

系统一般默认安装并启动了 crond 服务:

[root@stone ~]# systemctl status crond
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2023-07-31 09:02:10 CST; 1h 16min ago
 Main PID: 800 (crond)
    Tasks: 1
   Memory: 748.0K
   CGroup: /system.slice/crond.service
           └─800 /usr/sbin/crond -n

Jul 31 09:02:10 stone systemd[1]: Started Command Scheduler.
Jul 31 09:02:10 stone crond[800]: (CRON) INFO (Syslog will be used instead of sendmail.)
Jul 31 09:02:10 stone crond[800]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 9% if used.)
Jul 31 09:02:10 stone crond[800]: (CRON) INFO (running with inotify support)

crontab

使用 crontab 命令创建循环执行任务。

常用选项有:

  • -l:查看任务,实际上是查看 /var/spool/cron 目录下对应的文件
  • -e:编辑任务,使用 vi 编辑 /var/spool/cron 目录下对应的文件

创建一个在每天 12:30 执行的任务:

[root@stone ~]# crontab -e
30 12 * * * df -h >> /root/df.log 2>&1

其中:

  • 第 1 个字段表示分钟,0-59
  • 第 2 个字段表示小时,0-23
  • 第 3 个字段表示日期,1-31
  • 第 4 个字段表示月份,1-12
  • 第 5 个字段表示星期,0-7,0 和 7 都表示周日
  • 第 6 个字段表示命令

常用的日期格式有:

  • */5 * * * *:表示每 5 分钟执行一次
  • 15 * * * *:表示在每小时的 15 分钟时执行,如 00:15,01:15 等
  • 30 12 * * *:表示在每天的 12:30 执行
  • 30 10,20 * * *:表示在每天的 10:30 和 20:30 执行
  • 30 10-20 * * *:表示在每天的 10 点到 20点的每小时的 30 分钟执行
  • * 8-20/2 * * *:表示在每天的 10 点到 20点每隔 2 小时执行一次
  • 30 12 1 * *:表示在每月 1 号的 12:30 执行
  • 30 12 1 1 *:表示在每年 1 月 1 号的 12:30 执行
  • 30 12 * * 6:表示在每周 6 的 12:30 执行
  • @reboot:重启后执行
  • @hourly:每小时执行一次,等价于 0 * * * *
  • @daily:每天执行一次,等价于 0 0 * * *
  • @monthly:每月执行一次,等价于 0 0 1 * *
  • @yearly:每年执行一次,等价于 0 0 1 1 *
  • @weekly:每周执行一次,等价于 0 0 * * 0

查看任务:

[root@stone ~]# crontab -l
30 12 * * * df -h >> /root/df.log 2>&1

[root@stone ~]# cat /var/spool/cron/root 
30 12 * * * df -h >> /root/df.log 2>&1

可以从日志文件 /var/log/cron 查看执行情况。如果在任务执行过程中遇到找不到命令导致执行失败的问题,可以在脚本中读取环境变量文件,配置环境变量或者使用命令的绝对路径。

配置文件

除了使用 crontab 命令创建与业务相关的循环执行的任务外,还可以将系统相关的循环执行任务写入到 /etc/crontab 配置文件中:

[root@stone ~]# cat /etc/crontab 
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed

其中,SHELLPATHMAILTO 为环境变量,然后在最下面配置任务,格式与使用 crontab 命令类似,只是多了一个 user-name 字段,用来指定执行命令的用户。

除了在 /etc/crontab 文件中进行配置外,还可以针对特定的程序创建单独的循环执行任务配置文件,放到 /etc/cron.d 目录下:

[root@stone ~]# ll /etc/cron.d/
total 8
-rw-r--r--. 1 root root 128 Aug  9  2019 0hourly
-rw-------. 1 root root 235 Apr  1  2020 sysstat
[root@stone ~]# cat /etc/cron.d/0hourly 
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly

对于文件 /etc/cron.d/0hourly,最后一行表示在每小时的 1 分钟时使用 root 用户执行命令 run-parts /etc/cron.hourlyrun-parts 为一个 Shell 脚本,会在 5 分钟内一个随机时间点执行 /etc/cron.hourly 目录下的脚本。当前 /etc/cron.hourly 目录下的脚本为 0anacron

[root@stone ~]# ll /etc/cron.hourly/
total 4
-rwxr-xr-x. 1 root root 392 Aug  9  2019 0anacron

[root@stone ~]# cat /etc/cron.hourly/0anacron 
#!/bin/sh
# Check whether 0anacron was run today already
if test -r /var/spool/anacron/cron.daily; then
    day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
    exit 0;
fi

# Do not run jobs when on battery power
if test -x /usr/bin/on_ac_power; then
    /usr/bin/on_ac_power >/dev/null 2>&1
    if test $? -eq 1; then
    exit 0
    fi
fi
/usr/sbin/anacron -s

脚本 /etc/cron.hourly/0anacron 先读取目录 /var/spool/anacron/ 下的时间戳文件来判断当天是否已经执行 anacron 命令,如果时间戳文件中的时间与当前时间不一致,则执行命令 /usr/sbin/anacron -s

命令 anacron 会读取文件 /etc/anacrontab 中配置的计划任务并执行,-s 选项表示串行执行,前一个任务完成后才执行下一个:

[root@stone ~]# cat /etc/anacrontab 
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1       		  5       		 	 cron.daily       nice run-parts /etc/cron.daily
7       		  25      		 	 cron.weekly      nice run-parts /etc/cron.weekly
@monthly 		  45     			 cron.monthly     nice run-parts /etc/cron.monthly

其中:

  • period in days:表示执行周期,1 表示每天,7 表示每周,@monthly 表示每月
  • delay in minutes:延迟时间,避免同一时间执行导致资源争用
  • job-identifier:任务名称,用于日志文件
  • command:执行的命令,此处使用 run-parts 命令分别执行 /etc/cron.daily/etc/cron.weekly/etc/cron.monthly 目录下的文件

到这里可能会疑惑,为什么要额外使用 anacron 命令来处理每天,每周和每月的任务呢,这是由于如果直接使用 crond 来处理,如果当时系统处于宕机状态,待恢复启动后,已经过了设定的处理时间了,则 crond 就不会处理了,使用 anacron 就可以更加上次处理的时间戳来判断是否需要处理。

命令 anacron 会将执行时的时间戳写入到 /var/spool/anacron 目录下的文件中以便判断是否已经执行:

[root@stone ~]# more /var/spool/anacron/*
::::::::::::::
/var/spool/anacron/cron.daily
::::::::::::::
20230731
::::::::::::::
/var/spool/anacron/cron.monthly
::::::::::::::
20230704
::::::::::::::
/var/spool/anacron/cron.weekly
::::::::::::::
20230725

综上,系统处理循环任务的流程如下:

  1. crond 服务每分钟读取一次 /var/spool/cron/*/etc/cron.d/* /etc/crontab 文件,根据配置执行对应的任务
  2. 执行到 /etc/cron.d/0hourly 时,会执行 /etc/cron.hourly 目录下的脚本
  3. 执行到 /etc/cron.hourly/0anacron 时,会调用 anacron 命令执行文件 /etc/anacrontab 中配置的计划任务,包括 /etc/cron.daily/etc/cron.weekly/etc/cron.monthly 目录下的文件

image-20230731171400297

网络

在前面安装 CentOSopen in new window 时,是自动获取 IP 地址的,但是在实际工作中,通常都会为 Linux 服务器配置一个固定的 IP 地址。本节介绍如何管理 Linux 的网络。

文件

可以通过图形界面,文字界面菜单或者直接修改配置文件的方式来配置网络,这里只介绍通过修改配置文件来配置网络。

网口配置文件

在 Linux 中,每个网口都有一个对应的配置文件,位于 /etc/sysconfig/network-scripts/ 目录下,文件名为 ifcfg-INTERFACE_NAME,如果是 CentOS 6,一般默认为 ifcfg-eth0,如果是 CentOS 7,一般默认为 ifcfg-ens33

为 Linux 服务器配置固定 IP 的配置如下:

[root@stone ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE="Ethernet"
BOOTPROTO="none"
DEFROUTE="yes"
IPADDR=192.168.44.135
NETMASK=255.255.255.0
GATEWAY=192.168.44.2
NAME="ens33"
DEVICE="ens33"
ONBOOT="yes"
UUID="96350fad-1ffc-4410-a068-5d13244affb7"

其中:

  • TYPE:网口类型,一般为 "Ethernet"
  • BOOTPROTO:获取 IP 的方式。如果为 dhcp,表示自动获取 IP;如果为 static 或者 none,表示需手动配置 IP
  • DEFROUTE:默认路由接口
  • IPADDR:IP 地址
  • NETMASK:掩码地址
  • GATEWAY:网关地址
  • NAME:GUI 中显示的接口名称
  • DEVICE:物理网口名称
  • ONBOOT:接口是否在启动时激活
  • UUID:网口的 UUID

更多配置项请参考:Setting Up Networkingopen in new window 或者文件 /usr/share/doc/initscripts-*/sysconfig.txt

域名解析文件

使用 /etc/resolv.conf 文件指定 DNS 服务器以解析域名。

[root@stone ~]# cat /etc/resolv.conf 
; generated by /usr/sbin/dhclient-script
search localdomain
nameserver 192.168.44.2

其中:

  • search:默认仅包含本地域名。表示如果指定的主机名没有解析到,则会加上该域名作为后缀再次解析
  • nameserver:DNS 服务器地址,最多指定 3 个。

更多配置项请参考:resolv.conf(5) — Linux manual pageopen in new window 或者 man 5 resolv.conf

主机名与 IP 映射文件

使用 /etc/hosts 文件指定主机名与 IP 的映射,相当于静态的 DNS 解析。

[root@stone ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.44.135   stone

其中:

  • 192.168.44.135:IP 地址
  • stone:主机名

一定要将本机的 IP 地址和主机名配置到该文件中。

更详细的配置说明请参考:hosts(5) — Linux manual pageopen in new window 或者 man 5 hosts

服务

系统默认启用 network 服务来运行网络:

[root@stone ~]# systemctl status network
● network.service - LSB: Bring up/down networking
   Loaded: loaded (/etc/rc.d/init.d/network; bad; vendor preset: disabled)
   Active: active (exited) since Tue 2023-08-01 13:30:32 CST; 1h 54min ago
     Docs: man:systemd-sysv-generator(8)
  Process: 785 ExecStart=/etc/rc.d/init.d/network start (code=exited, status=0/SUCCESS)
    Tasks: 0
   Memory: 0B

Aug 01 13:30:27 stone systemd[1]: Starting LSB: Bring up/down networking...
Aug 01 13:30:28 stone network[785]: Bringing up loopback interface:  [  OK  ]
Aug 01 13:30:32 stone network[785]: Bringing up interface ens33:  [  OK  ]
Aug 01 13:30:32 stone systemd[1]: Started LSB: Bring up/down networking.

可以看到 network 不是原生的 systemd 服务,其启动还是调用的 /etc/rc.d/init.d/network start 命令。查看其开机启动的方法如下:

[root@stone ~]# systemctl enable network
network.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig network on

[root@stone ~]# chkconfig --list network

Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use 'systemctl list-unit-files'.
      To see services enabled on particular target use
      'systemctl list-dependencies [target]'.

network         0:off   1:off   2:on    3:on    4:on    5:on    6:off

修改完该配置文件后,需要重启 network 服务才能生效:

[root@stone ~]# systemctl restart network

另外还有一个 NetworkManager 服务,在生产环境中一般较少用到,建议关闭:

[root@stone ~]# systemctl stop NetworkManager
[root@stone ~]# systemctl disable NetworkManager

命令

修改以上配置文件后,除了服务,可以使用以下命令来管理网络。

ifconfig

使用 ifconfiginterface configure)命令配置网络接口。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install net-tools

常用选项有:

  • -a:列出所有网口
  • mtu:设置 MTU
  • up:启动网口
  • down:关闭网口

查看网口情况:

[root@stone ~]# ifconfig -v
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.44.135  netmask 255.255.255.0  broadcast 192.168.44.255
        inet6 fe80::20c:29ff:feb7:db9b  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:b7:db:9b  txqueuelen 1000  (Ethernet)
        RX packets 36005  bytes 45413634 (43.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 13831  bytes 1464515 (1.3 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 41894  bytes 2529563 (2.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 41894  bytes 2529563 (2.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

可以看到 ens33 网口和环回口都处于 UP, 其中:

  • mtu:最大传输单元(Maximum Transmission Unit)
  • inet:IPv4 地址
  • inet6:IPv6 地址
  • ether:MAC 地址
  • txqueuelen:传输队列长度
  • RX:接收包情况
  • TX:发送包情况

创建一个虚拟网口,并设定其 MTU:

[root@stone ~]# ifconfig ens33:0 192.168.44.136
[root@stone ~]# ifconfig ens33:0 mtu 9000
[root@stone ~]# ifconfig ens33:0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9000
        inet 192.168.44.136  netmask 255.255.255.0  broadcast 192.168.44.255
        ether 00:0c:29:b7:db:9b  txqueuelen 1000  (Ethernet)        
[root@stone ~]# ifconfig ens33:0 down

ifup ifdown

使用 ifup 或者 ifdown 命令启动或关闭在 /etc/sysconfig/network-scripts/ 目录下的网口。

[root@stone ~]# ifdown ens33
[root@stone ~]# ifup ens33

注意:

不要在终端执行 ifdown,否则无法连接到服务器。

route

使用 route 命令管理网关。

常用选项有:

  • -n:不显示主机名,显示 IP 地址

查看路由表:

[root@stone ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.44.2    0.0.0.0         UG    0      0        0 ens33
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 ens33
192.168.44.0    0.0.0.0         255.255.255.0   U     0      0        0 ens33

其中:

  • Destination:目的地址
  • Gateway:网关地址,0.0.0.0 表示本机
  • Genmask:掩码
  • Flags:包括:
    • U:启动(Up)
    • G:需要使用网关转发(Gateway)
  • Iface:网口

ip

使用 ip 命令管理网络。

语法:

ip [ OPTIONS ] OBJECT { COMMAND | help }

其中:

  • OPTIONS 包括:
    • -h:以易读单位显示
    • -s:显示统计数据
    • -d:以详细格式
    • -br:以简化格式
  • OBJECT 包括:
    • address:网口地址信息
    • link:网口信息
    • route:路由信息
  • COMMAND 与对象有关,包括:
    • add:增加
    • delete:删除
    • set:设置
    • show:显示

查看网口地址信息:

[root@stone ~]# ip -h -s address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
    RX: bytes  packets  errors  dropped overrun mcast   
    5.59M      92.6k    0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    5.59M      92.6k    0       0       0       0       
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b7:db:9b brd ff:ff:ff:ff:ff:ff
    inet 192.168.44.135/24 brd 192.168.44.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:feb7:db9b/64 scope link 
       valid_lft forever preferred_lft forever
    RX: bytes  packets  errors  dropped overrun mcast   
    45.6M      37.9k    0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    1.79M      15.0k    0       0       0       0
    
[root@stone ~]# ip -br address
lo               UNKNOWN        127.0.0.1/8 ::1/128 
ens33            UP             192.168.44.135/24 fe80::20c:29ff:feb7:db9b/64 

查看网口信息:

[root@stone ~]# ip -br link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP> 
ens33            UP             00:0c:29:b7:db:9b <BROADCAST,MULTICAST,UP,LOWER_UP> 

查看路由信息:

[root@stone ~]# ip route
default via 192.168.44.2 dev ens33 
169.254.0.0/16 dev ens33 scope link metric 1002 
192.168.44.0/24 dev ens33 proto kernel scope link src 192.168.44.135

ping

使用 ping 命令测试网络连通性。

常用选项有:

  • -c:执行次数
  • -w:超时秒数

先使用本机 IP 地址,以测试是否正确配置网口并启动:

[root@stone ~]# ping -c 3 192.168.44.135
PING 192.168.44.135 (192.168.44.135) 56(84) bytes of data.
64 bytes from 192.168.44.135: icmp_seq=1 ttl=64 time=0.037 ms
64 bytes from 192.168.44.135: icmp_seq=2 ttl=64 time=0.065 ms
64 bytes from 192.168.44.135: icmp_seq=3 ttl=64 time=0.094 ms

--- 192.168.44.135 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.037/0.065/0.094/0.024 ms

再使用本机主机名,以测试是否正确配置主机名和 IP 映射文件:

[root@stone ~]# ping -c 3 stone
PING stone (192.168.44.135) 56(84) bytes of data.
64 bytes from stone (192.168.44.135): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from stone (192.168.44.135): icmp_seq=2 ttl=64 time=0.116 ms
64 bytes from stone (192.168.44.135): icmp_seq=3 ttl=64 time=0.093 ms

--- stone ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.044/0.084/0.116/0.030 ms

再使用网关地址,以测试到网关的连通性:

[root@stone ~]# ping -c 3 192.168.44.2
PING 192.168.44.2 (192.168.44.2) 56(84) bytes of data.
64 bytes from 192.168.44.2: icmp_seq=1 ttl=128 time=0.158 ms
64 bytes from 192.168.44.2: icmp_seq=2 ttl=128 time=0.226 ms
64 bytes from 192.168.44.2: icmp_seq=3 ttl=128 time=0.378 ms

--- 192.168.44.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.158/0.254/0.378/0.091 ms

最后使用公网域名,以测试公网连通性及 DNS 是否配置正确:

[root@stone ~]# ping -c 3 www.baidu.com
PING www.a.shifen.com (14.119.104.189) 56(84) bytes of data.
64 bytes from 14.119.104.189 (14.119.104.189): icmp_seq=1 ttl=128 time=35.5 ms
64 bytes from 14.119.104.189 (14.119.104.189): icmp_seq=2 ttl=128 time=33.0 ms
64 bytes from 14.119.104.189 (14.119.104.189): icmp_seq=3 ttl=128 time=33.2 ms

--- www.a.shifen.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 33.095/33.967/35.537/1.122 ms

traceroute

使用 traceroute 命令跟踪从源地址到目的地址之间的节点情况。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install traceroute

常用选项有:

  • -n:不解析主机名,使用 IP 地址
  • -w:超时秒数,默认 5 秒
  • -T:使用 TCP
[root@stone ~]# traceroute -n -T www.baidu.com
traceroute to www.baidu.com (14.119.104.189), 30 hops max, 60 byte packets
 1  192.168.44.2  0.247 ms  0.109 ms  0.072 ms
 2  14.119.104.189  39.220 ms  45.048 ms  40.654 ms

netstat

使用 netstat 命令查看网络连接情况。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install net-tools

常用选项有:

  • -t:列出使用 TCP 的连接
  • -u:列出使用 UDP 的连接
  • -n:不解析主机名,使用 IP 地址
  • -a:列出所有状态的连接
  • -l:仅列出监听状态的连接
  • -p:列出连接对应 PID 及进程名称
  • -r:列出路由表
  • -i:列出网口情况
  • -s:列出各协议的统计信息
  • -c:执行连续显示的间隔秒数

列出主机当前网络连接情况:

[root@stone ~]# netstat -tunap
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:10051           0.0.0.0:*               LISTEN      1449/zabbix_server  
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      1009/php-fpm: maste 
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      758/rpcbind         
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1007/sshd           
tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      1029/zabbix_agentd  
tcp        0      0 127.0.0.1:10050         127.0.0.1:44174         TIME_WAIT   -                   
......
tcp        0     96 192.168.44.135:22       192.168.44.1:50404      ESTABLISHED 1700/sshd: root@pts 
tcp        0      0 127.0.0.1:10050         127.0.0.1:44218         TIME_WAIT   -                   
......
tcp        0      0 192.168.44.135:22       192.168.44.1:50221      ESTABLISHED 1542/sshd: root@pts 
tcp        0      0 127.0.0.1:10050         127.0.0.1:44146         TIME_WAIT   -                   
tcp        0      0 127.0.0.1:10050         127.0.0.1:44188         TIME_WAIT   -                   
tcp6       0      0 :::10051                :::*                    LISTEN      1449/zabbix_server  
tcp6       0      0 :::33060                :::*                    LISTEN      1389/mysqld         
tcp6       0      0 :::3306                 :::*                    LISTEN      1389/mysqld         
tcp6       0      0 :::111                  :::*                    LISTEN      758/rpcbind         
tcp6       0      0 :::80                   :::*                    LISTEN      1011/httpd          
tcp6       0      0 :::22                   :::*                    LISTEN      1007/sshd           
tcp6       0      0 :::10050                :::*                    LISTEN      1029/zabbix_agentd  
udp        0      0 0.0.0.0:111             0.0.0.0:*                           758/rpcbind         
udp        0      0 127.0.0.1:323           0.0.0.0:*                           768/chronyd         
udp        0      0 0.0.0.0:932             0.0.0.0:*                           758/rpcbind         
udp6       0      0 :::111                  :::*                                758/rpcbind         
udp6       0      0 ::1:323                 :::*                                768/chronyd         
udp6       0      0 :::932                  :::*                                758/rpcbind

其中:

  • Proto:协议
  • Local Address:本机地址和端口
  • Foreign Address:外部地址和端口
  • State:套接字状态,包括:
    • LISTEN:监听状态
    • ESTABLISHED:已建立连接
    • TIME_WAIT:套接字在关闭后等待处理仍在网络中的数据包
    • CLOSE_WAIT:外部连接已断开,等待套接字关闭
  • PID/Program name:进程 PID 及名称

查看路由表:

[root@stone ~]# netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.44.2    0.0.0.0         UG        0 0          0 ens33
169.254.0.0     0.0.0.0         255.255.0.0     U         0 0          0 ens33
192.168.44.0    0.0.0.0         255.255.255.0   U         0 0          0 ens33

查看网口情况:

[root@stone ~]# netstat -i
Kernel Interface table
Iface             MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
ens33            1500     2041      0      0 0          1487      0      0      0 BMRU
lo              65536    26605      0      0 0         26605      0      0      0 LRU

查看各协议统计信息:

[root@stone ~]# netstat -s
Ip:
    28768 total packets received
    0 forwarded
    0 incoming packets discarded
    28768 incoming packets delivered
    28201 requests sent out
    24 dropped because of missing route
Icmp:
    8 ICMP messages received
    3 input ICMP message failed.
    ICMP input histogram:
        timeout in transit: 6
        echo replies: 2
    18 ICMP messages sent
    0 ICMP messages failed
    ICMP output histogram:
        destination unreachable: 9
        echo request: 9
IcmpMsg:
        InType0: 2
        InType11: 6
        OutType3: 9
        OutType8: 9
Tcp:
    2690 active connections openings
    2687 passive connection openings
    1 failed connection attempts
    0 connection resets received
    2 connections established
    28320 segments received
    27838 segments send out
    0 segments retransmited
    0 bad segments received.
    22 resets sent
Udp:
    186 packets received
    9 packets to unknown port received.
    0 packet receive errors
    373 packets sent
    0 receive buffer errors
    0 send buffer errors
UdpLite:
TcpExt:
    2645 TCP sockets finished time wait in fast timer
    5 delayed acks sent
    2685 packets directly queued to recvmsg prequeue.
    64999 bytes directly received in process context from prequeue
    372 packet headers predicted
    2684 packets header predicted and directly queued to user
    11090 acknowledgments not containing data payload received
    402 predicted acknowledgments
    TCPRcvCoalesce: 5
    TCPAutoCorking: 2
    TCPOrigDataSent: 11649
IpExt:
    InBcastPkts: 245
    InOctets: 1889743
    OutOctets: 1912616
    InBcastOctets: 19865
    InNoECTPkts: 28818

持续查看某个端口的连接情况:

[root@stone ~]# netstat -c 2 -tunlp | grep 80
tcp6       0      0 :::80                   :::*                    LISTEN      1011/httpd          
tcp6       0      0 :::80                   :::*                    LISTEN      1011/httpd 

telnet

使用 telnet 命令检查主机端口是否开启。

[root@stone ~]# telnet www.baidu.com 443
Trying 14.119.104.254...
Connected to www.baidu.com.
Escape character is '^]'.
quit
Connection closed by foreign host.

host

使用 host 命令查找主机名对应的 IP。

[root@stone ~]# host www.baidu.com
www.baidu.com is an alias for www.a.shifen.com.
www.a.shifen.com has address 14.119.104.189
www.a.shifen.com has address 14.119.104.254

默认使用 /etc/resolv.conf 中指定的 DNS 服务器进行查找,也可以指定额外的 DNS 服务器:

[root@stone ~]# host www.baidu.com 114.114.114.114
Using domain server:
Name: 114.114.114.114
Address: 114.114.114.114#53
Aliases: 

www.baidu.com is an alias for www.a.shifen.com.
www.a.shifen.com has address 14.119.104.189
www.a.shifen.com has address 14.119.104.254

nslookup

使用 nslookup 命令查找主机名对应的 IP。

[root@stone ~]# nslookup www.baidu.com
Server:         192.168.44.2
Address:        192.168.44.2#53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com.
Name:   www.a.shifen.com
Address: 14.119.104.254
Name:   www.a.shifen.com
Address: 14.119.104.189

wget

使用 wget 命令下载文件。

常用选项有:

  • -b:后台下载
  • -c:断点续传
  • -i:下载文件中的多个链接
  • --limit-rate:限定速度
  • -O:下载另存为的文件名或标准输出
  • -q:关闭输出
[root@stone ~]# wget https://nginx.org/download/nginx-1.24.0.tar.gz
--2023-08-02 14:04:24--  https://nginx.org/download/nginx-1.24.0.tar.gz
Resolving nginx.org (nginx.org)... 3.125.197.172, 52.58.199.22, 2a05:d014:edb:5702::6, ...
Connecting to nginx.org (nginx.org)|3.125.197.172|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1112471 (1.1M) [application/octet-stream]
Saving to: ‘nginx-1.24.0.tar.gz’

100%[===============================================================================================>] 1,112,471   8.64KB/s   in 1m 48s 

2023-08-02 14:06:15 (10.0 KB/s) - ‘nginx-1.24.0.tar.gz’ saved [1112471/1112471]

如果文件较大,可以放入后台下载:

[root@stone ~]# wget -b https://wordpress.org/latest.zip
Continuing in background, pid 65237.
Output will be written to ‘wget-log’.

查看下载进度:

[root@stone ~]# tail -5f wget-log
 23850K .......... .......... .......... .......... .......... 99%  484K 0s
 23900K .......... .......... ....                            100%  394M=50s

2023-08-02 14:11:54 (476 KB/s) - ‘latest.zip’ saved [24498824/24498824]

curl

使用 curlClient URL)命令发出网络请求,获取数据。

语法:

curl [options] [URL...]

常用选项有:

  • -o:将服务器的回应保存成文件,等同于 wget 命令
  • -O:将下载内容保存为与 URL 中最后相同文件名的文件中
  • -C:断点续转
  • -s:静默下载,不显示进度信息
  • -S:只输出错误信息,通常与 -s 一起使用
  • -L:让 HTTP 请求跟随服务器的重定向,默认不跟随重定向
  • -d:用于发送 POST 请求的数据体
  • --data-urlencode:等同于 -d,发送 POST 请求的数据体,区别在于会自动将发送的数据进行 URL 编码
  • -X:指定 HTTP 请求的方法
  • -e:设置 HTTP 的标头 Referer,表示请求的来源
  • -A:指定客户端的用户代理标头,即 User-Agent
  • -H:添加 HTTP 请求的标头
  • -I:向服务器发出 HEAD 请求,将返回的 HTTP 标头打印出来
  • -u:设置服务器认证的用户名和密码
  • --limit-rate:限定下载速度
  • -w:定义在 HTTP 请求完成后的输出,使用格式字符串指定显示的信息,常用格式字符串有:
    • %{http_code}:响应码
    • %{size_download}:下载总大小
    • %{size_upload}:上传总大小
    • %{time_total}:请求总时间

下载文件:

[root@stone ~]# curl -C - -O http://mirrors.163.com/centos/RPM-GPG-KEY-CentOS-7
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1690  100  1690    0     0   4936      0 --:--:-- --:--:-- --:--:--  4941

[root@stone ~]# ll RPM-GPG-KEY-CentOS-7 
-rw-r--r--. 1 root root 1690 Sep  1 13:55 RPM-GPG-KEY-CentOS-7

查看网站是否运行正常:

[root@stone ~]# curl -s -o /dev/null -w "%{http_code}" stonecoding.net
200

tcpdump

使用 tcpdump 命令抓包分析流量。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install tcpdump

常用选项有:

  • -A:以 ASCII 显示
  • -i:指定网口
  • -q:简洁输出
  • -w:保存到指定文件
  • -r:读取由 -w 保存的文件
  • -c:指定抓包的数量
  • -nn:不解析主机名,使用 IP 地址

抓取 10 个来自主机 192.168.44.1 通过网口 ens33 访问端口 80 的包:

[root@stone ~]# tcpdump -nn -i ens33 port 80 and src host 192.168.44.1 -c 10
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
14:54:49.997080 IP 192.168.44.1.60899 > 192.168.44.135.80: Flags [.], ack 1978136764, win 4106, length 0
14:54:54.987000 IP 192.168.44.1.60899 > 192.168.44.135.80: Flags [F.], seq 0, ack 1, win 4106, length 0
14:54:54.987502 IP 192.168.44.1.60903 > 192.168.44.135.80: Flags [S], seq 3584808811, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
14:54:54.988363 IP 192.168.44.1.60903 > 192.168.44.135.80: Flags [.], ack 2205435186, win 513, length 0
14:54:54.988851 IP 192.168.44.1.60903 > 192.168.44.135.80: Flags [P.], seq 0:715, ack 1, win 513, length 715: HTTP: POST /zabbix/jsrpc.php?output=json-rpc HTTP/1.1
14:54:55.104190 IP 192.168.44.1.60903 > 192.168.44.135.80: Flags [.], ack 632, win 510, length 0
14:54:57.301486 IP 192.168.44.1.60903 > 192.168.44.135.80: Flags [P.], seq 715:1548, ack 632, win 510, length 833: HTTP: POST /zabbix/zabbix.php?sid=93439db26486f4ef&action=hintbox.eventlist HTTP/1.1
14:54:57.479394 IP 192.168.44.1.60903 > 192.168.44.135.80: Flags [.], ack 2003, win 513, length 0
14:55:01.433780 IP 192.168.44.1.60909 > 192.168.44.135.80: Flags [S], seq 2022463334, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
14:55:01.434935 IP 192.168.44.1.60909 > 192.168.44.135.80: Flags [.], ack 2706327158, win 513, length 0
10 packets captured
10 packets received by filter
0 packets dropped by kernel

ethtool

使用 ethtool 命令查看网卡信息。

常用选项有:

-S:查看网络使用情况

查看网卡信息:

[root@stone ~]# ethtool ens33
Settings for ens33:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Full 
        Advertised pause frame use: No
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Speed: 1000Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        MDI-X: off (auto)
        Supports Wake-on: d
        Wake-on: d
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: yes

查看网络使用情况:

[root@stone ~]# ethtool -S ens33
NIC statistics:
     rx_packets: 87
     tx_packets: 74
     rx_bytes: 10477
     tx_bytes: 13078
     rx_broadcast: 0
     tx_broadcast: 0
     rx_multicast: 0
     tx_multicast: 0
     rx_errors: 0
     tx_errors: 0
     tx_dropped: 0
     multicast: 0
     collisions: 0
     rx_length_errors: 0
     rx_over_errors: 0
     rx_crc_errors: 0
     rx_frame_errors: 0
     rx_no_buffer_count: 0
     rx_missed_errors: 0
     tx_aborted_errors: 0
     tx_carrier_errors: 0
     tx_fifo_errors: 0
     tx_heartbeat_errors: 0
     tx_window_errors: 0
     tx_abort_late_coll: 0
     tx_deferred_ok: 0
     tx_single_coll_ok: 0
     tx_multi_coll_ok: 0
     tx_timeout_count: 0
     tx_restart_queue: 0
     rx_long_length_errors: 0
     rx_short_length_errors: 0
     rx_align_errors: 0
     tx_tcp_seg_good: 0
     tx_tcp_seg_failed: 0
     rx_flow_control_xon: 0
     rx_flow_control_xoff: 0
     tx_flow_control_xon: 0
     tx_flow_control_xoff: 0
     rx_long_byte_count: 10477
     rx_csum_offload_good: 84
     rx_csum_offload_errors: 0
     alloc_rx_buff_failed: 0
     tx_smbus: 0
     rx_smbus: 0
     dropped_smbus: 0

SSH

在前面连接到 CentOSopen in new window 时,使用终端工具连接到 Linux,可以看到协议为 SSH。简单来说,SSH(Secure Shell)是一种网络协议,用于加密两台计算机之间的通信,保证远程登录和远程通信的安全。

SSH 协议的实现有多种,CentOS 默认使用 OpenSSH。SSH 架构为服务器-客户端模式,在这个架构中,SSH 软件分成两个部分:

  • 服务器:接收客户端发出的请求的部分,OpenSSH 的实现为 sshd
  • 客户端:向服务器发出请求的部分,OpenSSH 的实现为 ssh

服务器

OpenSSH 的服务端软件为 sshd,默认以后台服务的形式运行,

[root@stone ~]# systemctl status sshd.service
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2023-09-01 13:26:18 CST; 2h 56min ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 1014 (sshd)
   CGroup: /system.slice/sshd.service
           └─1014 /usr/sbin/sshd -D

Sep 01 13:26:18 localhost.localdomain systemd[1]: Starting OpenSSH server daemon...
Sep 01 13:26:18 localhost.localdomain sshd[1014]: Server listening on 0.0.0.0 port 22.
Sep 01 13:26:18 localhost.localdomain sshd[1014]: Server listening on :: port 22.
Sep 01 13:26:18 localhost.localdomain systemd[1]: Started OpenSSH server daemon.
Sep 01 13:29:07 localhost.localdomain sshd[1899]: Accepted password for root from 192.168.92.1 port 56824 ssh2
Sep 01 13:29:26 stone sshd[1951]: Accepted password for root from 192.168.92.1 port 56839 ssh2
Sep 01 13:37:26 stone sshd[1991]: Accepted password for root from 192.168.92.1 port 57222 ssh2
Sep 01 16:14:35 stone sshd[9916]: Accepted password for root from 192.168.92.1 port 56629 ssh2
Sep 01 16:14:38 stone sshd[9936]: Accepted password for root from 192.168.92.1 port 56634 ssh2

配置文件为:/etc/ssh/sshd_config

[root@stone ~]# cat /etc/ssh/sshd_config 
#       $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/local/bin:/usr/bin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
#PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile      .ssh/authorized_keys

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
PasswordAuthentication yes

# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
#KerberosUseKuserok yes

# GSSAPI options
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
#GSSAPIEnablek5users no

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
# WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux and may cause several
# problems.
UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#ShowPatchLevel no
#UseDNS yes
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

# no default banner path
#Banner none

# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS

# override default of no subsystems
Subsystem       sftp    /usr/libexec/openssh/sftp-server

# Example of overriding settings on a per-user basis
#Match User anoncvs
#       X11Forwarding no
#       AllowTcpForwarding no
#       PermitTTY no
#       ForceCommand cvs server

其中:

  • Port:指定 sshd 监听的端口,即客户端连接的端口,默认是 22
  • PasswordAuthentication:指定是否允许密码登录,默认值为yes
  • PermitEmptyPasswords:指定是否允许空密码登录,默认为yes
  • PermitRootLogin:指定是否允许 root 用户登录,默认为yes
  • PubkeyAuthentication:指定是否允许公钥登录,默认值为 yes
  • HostKey:指定服务器的密钥
  • MaxStartups:指定允许同时并发的 SSH 连接数量。如果设为 0,表示没有限制。设为 A:B:C 的形式,比如 MaxStartups 10:30:100,表示如果达到 10 个并发连接,后面的连接将有 30% 的概率被拒绝;如果达到 100 个并发连接,则后面的连接将 100% 被拒绝
  • PrintLastLog:指定是否打印上一次用户登录时间,默认值为 yes

如果修改了该配置文件,建议使用 sshd -t 命令检查语法是否正确。

客户端

OpenSSH 的服务端软件为 ssh,CentOS 默认安装该客户端。

使用 ssh 命令连接到远程 Linux 主机。

语法:

ssh [options] [user@]hostname [command]

常用选项有:

  • -p:指定端口,默认端口为 22

连接到远程 Linux 主机:

[root@stone ~]# ssh 192.168.92.129
The authenticity of host '192.168.92.129 (192.168.92.129)' can't be established.
ECDSA key fingerprint is SHA256:RthpTxXcV7xYM68bBvWB7Rl9lfg/wjRhTXV2+omPJpY.
ECDSA key fingerprint is MD5:c7:9e:98:c3:7e:cb:a8:12:87:bf:fd:6b:a3:d8:84:aa.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.92.129' (ECDSA) to the list of known hosts.
root@192.168.92.129's password: 
Last login: Fri Sep  1 20:42:02 2023 from 192.168.92.1

[root@zabbix ~]# logout
Connection to 192.168.92.129 closed.

第一次连接时会打印远程 Linux 主机的指纹并需要确认,指纹是远程 Linux 主机公钥的哈希值:

[root@zabbix ~]# ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
256 SHA256:RthpTxXcV7xYM68bBvWB7Rl9lfg/wjRhTXV2+omPJpY no comment (ECDSA)

确认后会将其保存到 ~/.ssh/known_hosts 文件中,后续就不再需要确认了。

[root@stone ~]# cat ~/.ssh/known_hosts
192.168.92.129 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNcVtR8pweYrJh2HlGyjAaQ4K1p8R6G97sXDmF16mtqk2Z7lSByOjoeMORBTtC4e/rJfKXKAR8whPAv4+mEc6/Q=

如果远程 Linux 主机的公钥发生了变化,则需要执行以下命令将原来的公钥指纹从 ~/.ssh/known_hosts 文件删除:

[root@stone ~]# ssh-keygen -R 192.168.92.129
# Host 192.168.92.129 found: line 1
/root/.ssh/known_hosts updated.
Original contents retained as /root/.ssh/known_hosts.old

连接到远程 Linux 主机执行命令:

[root@stone ~]# ssh root@192.168.92.129 hostname
The authenticity of host '192.168.92.129 (192.168.92.129)' can't be established.
ECDSA key fingerprint is SHA256:RthpTxXcV7xYM68bBvWB7Rl9lfg/wjRhTXV2+omPJpY.
ECDSA key fingerprint is MD5:c7:9e:98:c3:7e:cb:a8:12:87:bf:fd:6b:a3:d8:84:aa.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.92.129' (ECDSA) to the list of known hosts.
root@192.168.92.129's password: 
zabbix

SSH 客户端的全局配置文件是 /etc/ssh/ssh_config

[root@stone ~]# cat /etc/ssh/ssh_config 
#       $OpenBSD: ssh_config,v 1.30 2016/02/20 23:06:23 sobrado Exp $

# This is the ssh client system-wide configuration file.  See
# ssh_config(5) for more information.  This file provides defaults for
# users, and the values can be changed in per-user configuration files
# or on the command line.

# Configuration data is parsed as follows:
#  1. command line options
#  2. user-specific file
#  3. system-wide file
# Any configuration value is only changed the first time it is set.
# Thus, host-specific definitions should be at the beginning of the
# configuration file, and defaults at the end.

# Site-wide defaults for some commonly used options.  For a comprehensive
# list of available options, their meanings and defaults, please see the
# ssh_config(5) man page.

# Host *
#   ForwardAgent no
#   ForwardX11 no
#   RhostsRSAAuthentication no
#   RSAAuthentication yes
#   PasswordAuthentication yes
#   HostbasedAuthentication no
#   GSSAPIAuthentication no
#   GSSAPIDelegateCredentials no
#   GSSAPIKeyExchange no
#   GSSAPITrustDNS no
#   BatchMode no
#   CheckHostIP yes
#   AddressFamily any
#   ConnectTimeout 0
#   StrictHostKeyChecking ask
#   IdentityFile ~/.ssh/identity
#   IdentityFile ~/.ssh/id_rsa
#   IdentityFile ~/.ssh/id_dsa
#   IdentityFile ~/.ssh/id_ecdsa
#   IdentityFile ~/.ssh/id_ed25519
#   Port 22
#   Protocol 2
#   Cipher 3des
#   Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc
#   MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
#   EscapeChar ~
#   Tunnel no
#   TunnelDevice any:any
#   PermitLocalCommand no
#   VisualHostKey no
#   ProxyCommand ssh -q -W %h:%p gateway.example.com
#   RekeyLimit 1G 1h
#
# Uncomment this if you want to use .local domain
# Host *.local
#   CheckHostIP no

Host *
        GSSAPIAuthentication yes
# If this option is set to yes then remote X11 clients will have full access
# to the original X11 display. As virtually no X11 client supports the untrusted
# mode correctly we set this to yes.
        ForwardX11Trusted yes
# Send locale-related environment variables
        SendEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
        SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
        SendEnv LC_IDENTIFICATION LC_ALL LANGUAGE
        SendEnv XMODIFIERS

密钥登录

SSH 默认采用密码登录,有时候会需要使用密钥配置免密码登录。

SSH 密钥登录采用非对称加密,配置步骤如下:

  1. 客户端使用 ssh-keygen 在某个用户下生成自己的公钥和私钥。
[root@stone ~]# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Fwp8pnLRgBOmoAgVligCMSctakFi04rbBAsubmWgySc root@stone
The key's randomart image is:
+---[RSA 2048]----+
|@O*ooo.          |
|&O++o. o         |
|%==  .+ + .      |
|BE.+   * . .     |
|++= . o S .      |
|.o.  o   .       |
|.                |
|                 |
|                 |
+----[SHA256]-----+

这里使用默认的私钥文件名,不为私钥文件设定密码保护。生成的私钥为 ~/.ssh/id_rsa,公钥为 ~/.ssh/id_rsa.pub

[root@stone ~]# ll /root/.ssh/
-rw-------. 1 root root 1675 Sep  2 19:50 id_rsa
-rw-r--r--. 1 root root  392 Sep  2 19:50 id_rsa.pub
  1. 客户端使用 ssh-copy-id 命令,自动将公钥拷贝到远程服务器的 ~/.ssh/authorized_keys 文件中。如果 ~/.ssh/authorized_keys 文件不存在,会自动创建该文件。
[root@stone ~]# ssh-copy-id root@192.168.92.129
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.92.129's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.92.129'"
and check to make sure that only the key(s) you wanted were added.
  1. 进行测试,测试连接到远程服务器就不再需要密码了。
[root@stone ~]# ssh root@192.168.92.129
Last login: Sat Sep  2 19:47:58 2023 from 192.168.92.1
[root@zabbix ~]# 

客户端使用密钥访问远程服务器的过程如下:

  1. 客户端向服务器发起 SSH 登录的请求。
  2. 服务器收到客户端 SSH 登录的请求后,发送一些随机数据给客户端,要求客户端证明自己的身份。
  3. 客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。
  4. 服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许客户端登录。

命令

scp

使用 scpsecure copy)命令在服务器之间拷贝数据。它的底层是 SSH 协议,默认端口是 22,相当于先使用 ssh 命令登录远程主机,然后再执行拷贝操作。

scp 主要用于以下三种复制操作。

  • 本地复制到远程服务器。
  • 远程服务器复制到本地。
  • 两个远程服务器之间的复制。

语法:

scp [options] [[user@]host1:]file1 ... [[user@]host2:]file2

将源端一个或多个文件或目录复制到目标端,如果省略用户名,则为当前登录用户名,如果省略主机名,则为当前主机。

注意:

如果所要复制的文件,在目标位置已经存在同名文件,scp 会在没有警告的情况下覆盖同名文件。

常用选项有:

  • -r:以递归方式复制目录
  • -l:指定传输数据的带宽,单位为 Kbit/s
  • -P:指定连接到远程服务器的端口
  • -p:保留修改时间(modification time)、访问时间(access time)、权限(mode)等原文件信息
  • -q:静默模式

拷贝文件到远程服务器:

[root@stone ~]# scp dflog root@192.168.92.129:/root
dflog                100%  441    36.4KB/s   00:00    
[root@stone ~]# 

拷贝目录到远程服务器:

[root@stone ~]# scp -r d1 root@192.168.92.129:/root
f1                              100%   12     1.9KB/s   00:00    
f2                              100%   13     1.2KB/s   00:00    
f3                              100%   25    16.1KB/s   00:00

拷贝目录下的文件到远程服务器:

[root@stone ~]# scp -r d1/* root@192.168.92.129:/root
f1                              100%   12    19.7KB/s   00:00    
f2                              100%   13    23.6KB/s   00:00    
f3                              100%   25    29.2KB/s   00:00 

拷贝远程服务器目录到本地:

[root@stone ~]# scp -r root@192.168.92.129:/root/d1 .
f1                              100%   12    29.3KB/s   00:00    
f2                              100%   13    35.9KB/s   00:00    
f3                              100%   25    39.3KB/s   00:00

rsync

使用 rsyncremote sync)命令进行文件同步。可以在本地与远程主机之间,或者两个本地目录之间同步文件。

如果系统没有这个命令,使用 YUMopen in new window 进行安装,本地和远程主机都需要安装:

[root@stone ~]# yum -y install rsync

语法:

Local:  rsync [OPTION...] SRC... [DEST]
Access via remote shell:
Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
Push: rsync [OPTION...] SRC... [USER@]HOST:DEST

将源端一个或多个文件或目录同步到目标端,如果省略用户名,则为当前登录用户名,如果省略主机名,则为当前主机。

常用选项有:

  • -r:以递归方式复制目录
  • -a:等效于 -rlptgoD,比 -r 更常用,同步文件元数据
  • -l:等价于 --links,复制符号链接为符号链接
  • -p:保留权限
  • -t:保留修改时间
  • -g:保留属组
  • -o:保留用户
  • -D:等价于 --devices --specials,保留设备文件及特殊文件
  • -n:等价于 --dry-run,模拟运行
  • -v:输出信息
  • -z:等价于 --compress,传输时压缩文件
  • --delete:删除只存在于目标目录、不存在于源目录的文件,保存目录目录和源目录一致
  • --existing:不同步目标目录中不存在的文件
  • --ignore-existing:不同步目标目录已存在的文件
  • --exclude:排除指定文件
  • --include:包括指定文件
  • --progress:显示进度
  • --stats:显示文件传输状态

同步目录到远程主机,先模拟一下,没有问题再运行:

[root@stone ~]# rsync -anv --compress --stats d1 root@192.168.92.129:/root
sending incremental file list
d1/
d1/f1
d1/f2
d1/f3

Number of files: 4 (reg: 3, dir: 1)
Number of created files: 0
Number of deleted files: 0
Number of regular files transferred: 3
Total file size: 50 bytes
Total transferred file size: 50 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 0
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 114
Total bytes received: 29

sent 114 bytes  received 29 bytes  286.00 bytes/sec
total size is 50  speedup is 0.35 (DRY RUN)

[root@stone ~]# rsync -av --compress --stats d1 root@192.168.92.129:/root 
sending incremental file list
d1/
d1/f1
d1/f2
d1/f3

Number of files: 4 (reg: 3, dir: 1)
Number of created files: 0
Number of deleted files: 0
Number of regular files transferred: 3
Total file size: 50 bytes
Total transferred file size: 50 bytes
Literal data: 0 bytes
Matched data: 50 bytes
File list size: 0
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 216
Total bytes received: 95

sent 216 bytes  received 95 bytes  622.00 bytes/sec
total size is 50  speedup is 0.16

同步目录下新增的文件到远程主机:

[root@stone ~]# touch d1/f4
[root@stone ~]# rsync -av --compress --stats d1/ root@192.168.92.129:/root
sending incremental file list
./
f4

Number of files: 5 (reg: 4, dir: 1)
Number of created files: 1 (reg: 1)
Number of deleted files: 0
Number of regular files transferred: 1
Total file size: 50 bytes
Total transferred file size: 0 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 0
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 147
Total bytes received: 38

sent 147 bytes  received 38 bytes  370.00 bytes/sec
total size is 50  speedup is 0.27

程序

在 Windows 上,安装包的后缀名一般为 msi 或者 exe,在 CentOS 上,安装包的后缀名一般为 rpm

类似于 Windows 上的绿色软件,在 Linux 上也有一些软件,无需安装,解压即可使用。

本节介绍如何在 CentOS 上安装和卸载程序。

RPM

RPM(RedHat Package Manager)是一个运行在 RHEL、CentOS 和 Fedora 上的包管理系统,可以使用 RPM 分发、管理和更新程序。

rpm

使用 rpm 命令安装 RPM 程序包。

常用选项有:

  • -i:安装
  • -U:升级
  • -v:显示信息
  • -h:与 -v 配合显示进度
  • --nodeps:安装或升级时不检查依赖
  • -e:删除
  • -q:查询
  • -a:与 -q 配合,列出所有安装程序
  • -i:与 -q 配合,列出程序详细信息
  • -l:与 -q 配合,列出程序包含的文件
  • -c:与 -q 配合,列出程序的配置文件
  • -d:与 -q 配合,列出程序的帮助文件
  • -R:与 -q 配合,列出程序的依赖
  • -f:与 -q 配合,列出指定文件属于哪一个程序

安装程序:

[root@stone ~]# rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
Retrieving http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
warning: /var/tmp/rpm-tmp.eD4elk: Header V4 RSA/SHA1 Signature, key ID 7bd9bf62: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:nginx-release-centos-7-0.el7.ngx ################################# [100%]

程序名称中:

  • el7:表示 Enterprise Linux 7,这里就是 CentOS 7
  • noarch:表示不限制平台。可以是 i386 ,表示适用于 32 位 x86 平台;可以是 x86_64,表示适用于 64 位 x86 平台

查询是否安装了指定程序:

[root@stone ~]# rpm -qa | grep nginx-release
nginx-release-centos-7-0.el7.ngx.noarch

查询程序信息:

[root@stone ~]# rpm -qi nginx-release-centos-7-0.el7.ngx.noarch
Name        : nginx-release-centos
Version     : 7
Release     : 0.el7.ngx
Architecture: noarch
Install Date: Wed 02 Aug 2023 04:16:41 PM CST
Group       : System Environment/Base
Size        : 1576
License     : BSD
Signature   : RSA/SHA1, Tue 15 Jul 2014 10:44:38 PM CST, Key ID abf5bd827bd9bf62
Source RPM  : nginx-release-centos-7-0.el7.ngx.src.rpm
Build Date  : Tue 15 Jul 2014 10:44:01 PM CST
Build Host  : centos7-amd64-ovl
Relocations : (not relocatable)
URL         : http://nginx.org
Summary     : nginx repo configuration and pgp public keys
Description :
yum config files for nginx repository, and nginx public signing key.
After the package installation you will be able to import the key
to rpm with the "rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-nginx"
command, and turn on option gpgcheck in /etc/yum.repos.d/nginx.repo

查看程序包含的文件:

[root@stone ~]# rpm -ql nginx-release-centos-7-0.el7.ngx.noarch
/etc/pki/rpm-gpg/RPM-GPG-KEY-nginx
/etc/yum.repos.d/nginx.repo

查看程序的配置文件:

[root@stone ~]# rpm -qc nginx-release-centos-7-0.el7.ngx.noarch
/etc/yum.repos.d/nginx.repo

查看文件属于哪个程序:

[root@stone ~]# rpm -qf /etc/yum.repos.d/nginx.repo
nginx-release-centos-7-0.el7.ngx.noarch

删除程序:

[root@stone ~]# rpm -e nginx-release-centos-7-0.el7.ngx.noarch

YUM

使用 RPM 经常会遇到缺少依赖的问题,此时可以使用 YUM(Yellow Dog Updater, Modified)来进行安装。YUM 在更新、安装或删除程序时自动解析依赖关系,自动获取和安装所有可用的依赖包。

那么 YUM 在什么地方去获取依赖包呢?先来看看 YUM 的配置文件 /etc/yum.conf

[root@stone ~]# cat /etc/yum.conf 
[main]
cachedir=/var/cache/yum/$basearch/$releasever
keepcache=0
debuglevel=2
logfile=/var/log/yum.log
exactarch=1
obsoletes=1
gpgcheck=1
plugins=1
installonly_limit=5
bugtracker_url=http://bugs.centos.org/set_project.php?project_id=23&ref=http://bugs.centos.org/bug_report_page.php?category=yum
distroverpkg=centos-release


#  This is the default, if you make this bigger yum won't see if the metadata
# is newer on the remote and so you'll "gain" the bandwidth of not having to
# download the new metadata and "pay" for it by yum not having correct
# information.
#  It is esp. important, to have correct metadata, for distributions like
# Fedora which don't keep old packages around. If you don't like this checking
# interupting your command line usage, it's much better to have something
# manually check the metadata once an hour (yum-updatesd will do this).
# metadata_expire=90m

# PUT YOUR REPOS HERE OR IN separate files named file.repo
# in /etc/yum.repos.d

其中 [main] 部分是 YUM 的全局配置,包括:

  • cachedir:YUM 的缓存及数据库文件,默认为 /var/cache/yum/$basearch/$releasever,这里有两个变量:

    • $basearch:系统平台,可以使用 arch 命令获取:
    [root@stone ~]# arch
    x86_64
    
    • $releasever:系统版本,从上面的 distroverpkg 中获取当前系统为 centos-release,再使用 rpm -qi 获取其版本:
    [root@stone ~]# rpm -qi centos-release
    Name        : centos-release
    Version     : 7
    Release     : 8.2003.0.el7.centos
    Architecture: x86_64
    Install Date: Wed 06 Jan 2021 09:48:10 AM CST
    Group       : System Environment/Base
    Size        : 43849
    License     : GPLv2
    Signature   : RSA/SHA256, Tue 14 Apr 2020 11:54:48 PM CST, Key ID 24c6a8a7f4a80eb5
    Source RPM  : centos-release-7-8.2003.0.el7.centos.src.rpm
    Build Date  : Wed 08 Apr 2020 06:01:12 AM CST
    Build Host  : x86-01.bsys.centos.org
    Relocations : (not relocatable)
    Packager    : CentOS BuildSystem <http://bugs.centos.org>
    Vendor      : CentOS
    Summary     : CentOS Linux release file
    Description :
    CentOS Linux release files
    

    可以看到 Version 为 7,故 cachedir/var/cache/yum/x86_64/7

    直接使用以下命令查看最终的变量值:

    [root@stone ~]# python -c 'import yum, json; yb = yum.YumBase(); print json.dumps(yb.conf.yumvar, indent=2)'
    Loaded plugins: fastestmirror
    {
      "uuid": "4380d371-2a81-4aa8-ad89-87fe599cdd54", 
      "contentdir": "centos", 
      "basearch": "x86_64", 
      "infra": "stock", 
      "releasever": "7", 
      "arch": "ia32e"
    }
    
  • logfile:日志文件

配置文件最下面建议将仓库文件放到 /etc/yum.repos.d 目录中,并以 .repo 作为文件后缀名。

安装完成 CentOS 后,/etc/yum.repos.d 目录下默认会有以下文件:

[root@stone ~]# ll /etc/yum.repos.d/
total 40
-rw-r--r--. 1 root root 1664 Oct 23  2020 CentOS-Base.repo
-rw-r--r--. 1 root root 1309 Oct 23  2020 CentOS-CR.repo
-rw-r--r--. 1 root root  649 Oct 23  2020 CentOS-Debuginfo.repo
-rw-r--r--. 1 root root  314 Oct 23  2020 CentOS-fasttrack.repo
-rw-r--r--. 1 root root  630 Oct 23  2020 CentOS-Media.repo
-rw-r--r--. 1 root root 1331 Oct 23  2020 CentOS-Sources.repo
-rw-r--r--. 1 root root 8515 Oct 23  2020 CentOS-Vault.repo
-rw-r--r--. 1 root root  616 Oct 23  2020 CentOS-x86_64-kernel.repo

在上面每个文件中,配置了一个或者多个仓库,就可以从这些仓库下载安装程序及其依赖。

文件 CentOS-Base.repo 内容如下:

[root@stone ~]# cat /etc/yum.repos.d/CentOS-Base.repo 
# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the 
# remarked out baseurl= line instead.
#
#

[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#released updates 
[updates]
name=CentOS-$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

其中:

http://mirrors.huaweicloud.com/centos/7.9.2009/os/x86_64/
http://mirrors.ustc.edu.cn/centos/7.9.2009/os/x86_64/
http://mirrors.nju.edu.cn/centos/7.9.2009/os/x86_64/
http://mirrors.tuna.tsinghua.edu.cn/centos/7.9.2009/os/x86_64/
http://mirrors.jlu.edu.cn/centos/7.9.2009/os/x86_64/
http://mirrors.cqu.edu.cn/CentOS/7.9.2009/os/x86_64/
http://mirrors.bupt.edu.cn/centos/7.9.2009/os/x86_64/
http://mirrors.bfsu.edu.cn/centos/7.9.2009/os/x86_64/
http://mirror.nyist.edu.cn/centos/7.9.2009/os/x86_64/
http://mirrors.qlu.edu.cn/centos/7.9.2009/os/x86_64/
  • baseurl:指定一个或者多个仓库的 URL

如果系统自带的仓库不能满足要求,还可以添加额外的仓库。比如前面使用 rpm 命令安装程序 nginx-release-centos-7-0.el7.ngx.noarch,实际上就是将文件 nginx.repo 拷贝到目录 /etc/yum.repos.d 中,增加一个 NGINX 仓库:

[root@stone ~]# cat /etc/yum.repos.d/nginx.repo 
# nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

其中:

  • [nginx]:仓库名称
  • baseurl:仓库地址
  • enabled:是否启用

配置好仓库后,就可以使用 yum 命令安装程序了。

yum

使用 yum 命令安装程序。

常用选项有:

  • -y:对于安装过程中提出的问题,统一回答为 Yes

常用子命令有:

  • install:安装程序
  • localinstall:安装本地 RPM 程序
  • update:更新程序
  • remove:删除程序
  • search:查找程序
  • list:列出程序
  • info:列出程序信息
  • repolist:列出仓库
  • provides:查找命令对应的安装包
  • history:列出安装历史
  • clean:删除缓存数据
  • makecache:生成缓存数据

查看配置的仓库:

[root@stone ~]# yum repolist
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.huaweicloud.com
 * extras: mirrors.huaweicloud.com
 * updates: mirrors.huaweicloud.com
repo id                                 repo name                                 status
base/7/x86_64                           CentOS-7 - Base                           10,072
extras/7/x86_64                         CentOS-7 - Extras                            518
updates/7/x86_64                        CentOS-7 - Updates                         5,061
nginx/x86_64                            nginx repo                                   318
repolist: 15,969

查找程序:

[root@stone ~]# yum search nginx

安装程序:

[root@stone ~]# yum install nginx

安装程序,无需确认:

[root@stone ~]# yum install -y bash-completion

查看是否安装了某个程序:

[root@stone ~]# yum list nginx
[root@stone ~]# yum list | grep nginx

查看程序信息:

[root@stone ~]# yum info nginx
Installed Packages
Name        : nginx
Arch        : x86_64
Epoch       : 1
Version     : 1.20.1
Release     : 10.el7
Size        : 1.7 M
Repo        : installed
From repo   : epel
Summary     : A high performance web server and reverse proxy server
URL         : https://nginx.org
License     : BSD
Description : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
            : IMAP protocols, with a strong focus on high concurrency, performance and low
            : memory usage.

查看命令对应的安装包:

[root@ebst2 ~]# yum provides */netstat
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.cqu.edu.cn
 * extras: mirrors.nju.edu.cn
 * updates: mirrors.cqu.edu.cn
net-tools-2.0-0.25.20131004git.el7.x86_64 : Basic networking tools
Repo        : base
Matched from:
Filename    : /bin/netstat



net-tools-2.0-0.25.20131004git.el7.x86_64 : Basic networking tools
Repo        : @base
Matched from:
Filename    : /bin/netstat

yum-config-manager

使用 yum-config-manager 命令修改 YUM 配置文件。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install yum-utils -y

常用选项有:

  • --add-repo:增加仓库
  • --enable:启用仓库
  • --disable:禁用仓库

增加阿里云的 Docker 仓库:

[root@stone ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Loaded plugins: fastestmirror
adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
grabbing file https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
repo saved to /etc/yum.repos.d/docker-ce.repo

禁用 NGINX 仓库:

[root@stone ~]# yum-config-manager --disable nginx
[root@stone ~]# cat /etc/yum.repos.d/nginx.repo 
# nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=0

启用 NGINX 仓库:

[root@stone ~]# yum-config-manager --enable nginx
[root@stone ~]# cat /etc/yum.repos.d/nginx.repo 
# nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

公网 YUM

如果服务器可以访问公网,则可以直接使用公网 YUM 安装程序,常用的公网 YUM 有:

具体使用方法参考官方帮助文档,这里以使用阿里云 CentOS 7 镜像为例:

备份配置文件:

[root@stone ~]# mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

下载配置文件:

[root@stone ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

-- 或者

[root@stone ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

生成缓存:

[root@stone ~]# yum makecache

本地 YUM

系统默认的 YUM 仓库都位于公网,如果服务器不能访问公网,可以使用安装系统的 ISO 映像文件配置一个本地 YUM 仓库。

  1. 挂载 ISO 映像文件到系统
[root@stone ~]# mount /dev/cdrom /media/
[root@stone ~]# ls /media/
CentOS_BuildTag  EULA  images    LiveOS    repodata              RPM-GPG-KEY-CentOS-Testing-7
EFI              GPL   isolinux  Packages  RPM-GPG-KEY-CentOS-7  TRANS.TBL
  1. 备份原仓库文件
[root@stone ~]# cd /etc/yum.repos.d/
[root@stone yum.repos.d]# mkdir bak
[root@stone yum.repos.d]# mv *.repo bak/
  1. 添加仓库,在 /etc/yum.repos.d 目录下创建 CentOS-Local.repo
[root@stone yum.repos.d]# vi CentOS-Local.repo
[local]
name=CentOS Local
baseurl=file:///media/
gpgcheck=0
enabled=1
  1. 清除并重建缓存
[root@stone yum.repos.d]# yum clean all
Loaded plugins: fastestmirror
Cleaning repos: local
Cleaning up list of fastest mirrors

[root@stone yum.repos.d]# yum makecache
Loaded plugins: fastestmirror
Determining fastest mirrors
local                                                           | 3.6 kB  00:00:00     
(1/4): local/group_gz                                           | 3.5 kB  00:00:00     
(2/4): local/primary_db                                         | 830 kB  00:00:00     
(3/4): local/other_db                                           | 203 kB  00:00:00     
(4/4): local/filelists_db                                       | 304 kB  00:00:00     
Metadata Cache Created

[root@stone yum.repos.d]# yum repolist
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
repo id                                 repo name                                     status
local                                   CentOS Local                                  446
repolist: 446

局域网 YUM

对于企业来说,为每个服务器配置本地 YUM 太麻烦了,可以使用 NGINX 为可以上公网的服务器配置局域网 YUM,其他不能上公网的服务器访问局域网 YUM 来安装程序。

  1. 安装 NGINX
[root@stone ~]# yum install nginx
  1. 拷贝 ISO 映像文件到指定目录
[root@stone ~]# mount /dev/cdrom /media/
[root@stone ~]# mkdir -p /usr/local/nginx/html/centos/7/os/x86_64
[root@stone ~]# cp - /media/* /usr/local/nginx/html/centos/7/os/x86_64
[root@stone ~]# ls /usr/local/nginx/html/centos/7/os/x86_64
CentOS_BuildTag  EULA  images    LiveOS    repodata              RPM-GPG-KEY-CentOS-Testing-7
EFI              GPL   isolinux  Packages  RPM-GPG-KEY-CentOS-7  TRANS.TBL
  1. 配置 NGINX
[root@stone ~]# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
[root@stone ~]# vi /etc/nginx/nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
    client_max_body_size 500M;

    include /etc/nginx/conf.d/*.conf;

    server {
       listen 80;
       server_name 192.168.44.135;
       location / {
            root   /usr/local/nginx/html/centos;
            autoindex on;
            try_files $uri $uri/ /index.html;
       }
     }

}

[root@stone ~]# systemctl start nginx
[root@stone ~]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
[root@stone ~]# systemctl status nginx
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2023-08-03 15:49:07 CST; 21s ago
     Docs: http://nginx.org/en/docs/
 Main PID: 7804 (nginx)
   CGroup: /system.slice/nginx.service
           ├─7804 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
           ├─7805 nginx: worker process
           └─7806 nginx: worker process

Aug 03 15:49:07 stone systemd[1]: Starting nginx - high performance web server...
Aug 03 15:49:07 stone systemd[1]: Started nginx - high performance web server.
  1. 其他服务器配置 YUM
[root@stone ~]# cd /etc/yum.repos.d/
[root@stone yum.repos.d]# mkdir bak
[root@stone yum.repos.d]# mv *.repo bak/
[root@stone yum.repos.d]# vi CentOS-Local.repo
[local]
name=CentOS Local
baseurl=http://192.168.44.135/$releasever/os/$basearch/
gpgcheck=0
enabled=1

[root@stone yum.repos.d]# yum clean all
Loaded plugins: fastestmirror
Cleaning repos: local
Cleaning up list of fastest mirrors
Other repos take up 227 M of disk space (use --verbose for details)

[root@stone yum.repos.d]# yum makecache
Loaded plugins: fastestmirror
Determining fastest mirrors
local                                                                    | 3.6 kB  00:00:00     
(1/4): local/7/x86_64/group_gz                                           | 3.5 kB  00:00:00     
(2/4): local/7/x86_64/primary_db                                         | 830 kB  00:00:00     
(3/4): local/7/x86_64/filelists_db                                       | 304 kB  00:00:00     
(4/4): local/7/x86_64/other_db                                           | 203 kB  00:00:00     
Metadata Cache Created

[root@stone ~]# yum repolist
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
repo id                                       repo name                                   status
local/7/x86_64                                CentOS Local                                446
repolist: 446

日志

在系统出现问题后,首先需要做的就是查看对应的日志,找到问题的原因。本节介绍 CentOS 的日志管理。

服务

在 CentOS 7 中,管理日志的服务为 rsyslog,默认启动。

[root@stone ~]# systemctl status rsyslog
● rsyslog.service - System Logging Service
   Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2023-08-04 10:43:24 CST; 4min 13s ago
     Docs: man:rsyslogd(8)
           http://www.rsyslog.com/doc/
 Main PID: 1012 (rsyslogd)
    Tasks: 3
   Memory: 1.8M
   CGroup: /system.slice/rsyslog.service
           └─1012 /usr/sbin/rsyslogd -n

Aug 04 10:43:24 stone systemd[1]: Starting System Logging Service...
Aug 04 10:43:24 stone rsyslogd[1012]:  [origin software="rsyslogd" swVersion="8.24.0-52.el7" x-pid="1012" x-info="http://www.rsy..."] start
Aug 04 10:43:24 stone systemd[1]: Started System Logging Service.
Hint: Some lines were ellipsized, use -l to show in full.

该服务的配置文件为 /etc/rsyslog.conf

[root@stone ~]# cat /etc/rsyslog.conf 
# rsyslog configuration file

# For more information see /usr/share/doc/rsyslog-*/rsyslog_conf.html
# If you experience problems, see http://www.rsyslog.com/doc/troubleshoot.html

#### MODULES ####

# The imjournal module bellow is now used as a message source instead of imuxsock.
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
$ModLoad imjournal # provides access to the systemd journal
#$ModLoad imklog # reads kernel messages (the same are read from journald)
#$ModLoad immark  # provides --MARK-- message capability

# Provides UDP syslog reception
#$ModLoad imudp
#$UDPServerRun 514

# Provides TCP syslog reception
#$ModLoad imtcp
#$InputTCPServerRun 514


#### GLOBAL DIRECTIVES ####

# Where to place auxiliary files
$WorkDirectory /var/lib/rsyslog

# Use default timestamp format
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

# File syncing capability is disabled by default. This feature is usually not required,
# not useful and an extreme performance hit
#$ActionFileEnableSync on

# Include all config files in /etc/rsyslog.d/
$IncludeConfig /etc/rsyslog.d/*.conf

# Turn off message reception via local log socket;
# local messages are retrieved through imjournal now.
$OmitLocalLogging on

# File to store the position in the journal
$IMJournalStateFile imjournal.state


#### RULES ####

# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.*                                                 /dev/console

# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none                /var/log/messages

# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure

# Log all the mail messages in one place.
mail.*                                                  -/var/log/maillog


# Log cron stuff
cron.*                                                  /var/log/cron

# Everybody gets emergency messages
*.emerg                                                 :omusrmsg:*

# Save news errors of level crit and higher in a special file.
uucp,news.crit                                          /var/log/spooler

# Save boot messages also to boot.log
local7.*                                                /var/log/boot.log


# ### begin forwarding rule ###
# The statement between the begin ... end define a SINGLE forwarding
# rule. They belong together, do NOT split them. If you create multiple
# forwarding rules, duplicate the whole block!
# Remote Logging (we use TCP for reliable delivery)
#
# An on-disk queue is created for this action. If the remote host is
# down, messages are spooled to disk and sent when it is up again.
#$ActionQueueFileName fwdRule1 # unique name prefix for spool files
#$ActionQueueMaxDiskSpace 1g   # 1gb space limit (use as much as possible)
#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown
#$ActionQueueType LinkedList   # run asynchronously
#$ActionResumeRetryCount -1    # infinite retries if host is down
# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional
#*.* @@remote-host:514
# ### end of the forwarding rule ###

其中:

  • 第 55 行表示除了 mailauthprivcron 外,其他类型的 info 及以上级别日志写入到 /var/log/messages 文件,经常用到。
  • 第 58 行表示将 authpriv 类型的所有级别日志写入到 /var/log/secure 文件。
  • 第 61 行表示将 mail 类型的所有级别日志写入到 /var/log/maillog 文件。
  • 第 65 行表示将 cron 类型的所有级别日志写入到 /var/log/cron 文件。

命令

可以使用以下命令查看相关日志。

last

使用 last 命令查看用户登录日志以及系统启动记录,默认读取 /var/log/wtmp 文件中的数据。

[root@stone ~]# last -5
root     pts/1        192.168.44.1     Fri Aug  4 10:47   still logged in   
root     pts/0        192.168.44.1     Fri Aug  4 10:47   still logged in   
reboot   system boot  3.10.0-1127.el7. Fri Aug  4 10:43 - 15:27  (04:43)    
root     pts/2        192.168.44.1     Thu Aug  3 13:51 - down   (02:38)    
root     pts/1        192.168.44.1     Thu Aug  3 10:16 - down   (06:13)    

wtmp begins Wed Jan  6 09:52:58 2021

dmesg

使用 dmesg 命令查看系统启动信息。

[root@stone ~]# dmesg | head -5
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.10.0-1127.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Tue Mar 31 23:36:51 UTC 2020
[    0.000000] Command line: BOOT_IMAGE=/vmlinuz-3.10.0-1127.el7.x86_64 root=/dev/mapper/centos-root ro spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8

logger

使用 logger 命令将信息写入到日志。

常用选项有:

  • -t:为每一行日志指定标签,默认为用户名。
[root@stone ~]# logger "test logger"
[root@stone ~]# tail -1 /var/log/messages
Aug  4 16:13:19 stone root: test logger

日志轮转

随着系统的运行,日志越来越多,为节约磁盘空间,使用日志轮转来自动删除过期的日志。

在 CentOS 中,使用 crond 服务每天调用 logrotate 命令来轮转日志,其脚本为 /etc/cron.daily/logrotate

[root@stone ~]# cat /etc/cron.daily/logrotate
#!/bin/sh

/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

其中:

  • /var/lib/logrotate/logrotate.status:被轮转的日志文件将会写入到此文件中
  • /etc/logrotate.conflogrotate 命令的配置文件

查看 logrotate 命令配置文件:

[root@stone ~]# cat /etc/logrotate.conf 
# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# uncomment this if you want your log files compressed
#compress

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}

# system-specific logs may be also be configured here.

其中:

  • weekly:轮转周期,表示每周轮转一次,还可以是 hourly 每小时轮转一次, daily 每天轮转一次,monthly 每月轮转一次,yearly 每年轮转一次。
  • rotate 4:保留 4 个轮转周期。如果轮转周期为 weekly,则会保留之前 4 周的日志。
  • create:重命名日志后创建一个新的空日志文件。
  • dateext:为轮转后的日志增加日期后缀。
  • compress:压缩

以上为通用配置,后面指定需要轮转的日志及单独的配置,会覆盖通用配置:

  • include /etc/logrotate.d:各个日志的轮转配置

从通用配置可以看出,默认对日志文件每周轮转一次,保留 4 周,比如对于 /var/log/message 日志,其单独的配置为:

[root@stone ~]# cat /etc/logrotate.d/syslog
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
    missingok
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

根据通用配置和单独的配置,生成的日志文件如下:

[root@stone ~]# ll /var/log/messages*
-rw------- 1 root root  594820 Aug  4 16:40 /var/log/messages
-rw------- 1 root root  620367 Jul 11 09:23 /var/log/messages-20230711
-rw------- 1 root root 1041844 Jul 18 09:11 /var/log/messages-20230718
-rw------- 1 root root 1229574 Jul 25 10:10 /var/log/messages-20230725
-rw------- 1 root root 1006144 Aug  1 09:01 /var/log/messages-20230801

可以看到,除了当前使用的日志外,还有 4 个以日期为后缀的日志文件。

有的程序会自带日志轮转配置文件,例如 NGINX:

[root@stone ~]# cat /etc/logrotate.d/nginx 
/var/log/nginx/*.log {
        daily
        missingok
        rotate 52
        compress
        delaycompress
        notifempty
        create 640 nginx adm
        sharedscripts
        postrotate
                if [ -f /var/run/nginx.pid ]; then
                        kill -USR1 `cat /var/run/nginx.pid`
                fi
        endscript
}

如果程序没有自带日志轮转配置文件,可以根据需要在 /etc/logrotate.d/ 目录下创建,例如对于 Oracle 的日志文件,可以配置如下:

[root@fmesdbd1 ~]# cat /etc/logrotate.d/oracle 
/u01/app/oracle/diag/rdbms/test/test/trace/alert_test.log
/u01/app/oracle/diag/tnslsnr/stone/listener/trace/listener.log
{
rotate 12
copytruncate
monthly
dateext
nocompress
missingok
notifempty
}

其中:

  • copytruncate:与 create 不同,拷贝日志文件后,再清空日志文件。
  • notifempty:如果日志文件为空,则不轮转日志文件。

性能

在硬件确定的情况下,可以通过调整内核参数和资源限制来优化 Linux 性能。

内核参数

Linux 有很多内核参数,启动后目录 /proc/sys 下的文件对应内核参数名称:

[root@stone ~]# ls /proc/sys
abi  crypto  debug  dev  fs  kernel  net  sunrpc  user  vm
[root@stone ~]# cat /proc/sys/net/ipv4/ip_forward
1
类别描述
abiExecution domains and personalities
cryptoCryptographic interfaces
debugKernel debugging interfaces
devDevice specific information
fsGlobal and specific filesystem tunables
kernelGlobal kernel tunables
netNetwork tunables
sunrpcSun Remote Procedure Call (NFS)
userUser Namespace limits
vmTuning and management of memory, buffer, and cache

除了直接查看内核参数对应的文件,还可以使用命令 sysctl 查看内核参数的值:

[root@stone ~]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

使用 -a 选项查看所有内核参数:

[root@stone ~]# sysctl -a | grep ip_forward
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_use_pmtu = 0

常用的内核参数有:

  • fs.aio-max-nr:最大允许 AIO 请求数量,默认 65536
  • fs.file-max:所有进程能够同时打开的文件句柄数量,默认 395458
  • kernel.shmall:共享内存的总页数,默认 18446744073692774399
  • kernel.shmmax:单个共享内存段的最大值,默认 18446744073692774399 字节
  • kernel.shmmni:共享内存段的最大数量,默认 4096
  • kernel.sem:包含 4 个值,其中
    • semmsl:第 1 个值,表示一个信号量集合中能够包含的信号量最大数目,默认 250
    • semmns:第 2 个值,表示允许的信号量最大数目(semmsl * semmni),默认 32000
    • semopm:第 3 个值,表示单个 semopm() 调用在一个信号量集合上可以执行的操作数量,默认 32
    • semmni:第 4 个值,表示信号量集合总数,默认 128
  • net.ipv4.ip_local_port_range:应用程序可使用的 IPv4 端口范围,默认 32768 60999
  • net.core.rmem_default:套接字接收缓冲区大小的缺省值,默认 212992 字节
  • net.core.rmem_max:接字接收缓冲区大小的最大值,默认 212992 字节
  • net.core.wmem_default:套接字发送缓冲区大小的缺省值,默认 212992 字节
  • net.core.wmem_max:套接字发送缓冲区大小的最大值,默认 212992 字节
  • vm.min_free_kbytes:最小保留多少空闲内存空间,默认 67584 KB
  • vm.nr_hugepages:大页内存值,默认 0
  • vm.swappiness:控制对 Swap 的使用,越大越倾向于使用 Swap,默认 60

可以直接修改 /proc/sys 下的文件以修改内核参数,但是重启后失效。如果要永久更改,则需要修改 /etc/sysctl.conf 文件或者在目录 /etc/sysctl.d/ 下创建配置文件:

[root@stone ~]# cat /etc/sysctl.conf
# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
#
# Vendors settings live in /usr/lib/sysctl.d/.
# To override a whole file, create a new file with the same in
# /etc/sysctl.d/ and put new settings there. To override
# only specific settings, add a file with a lexically later
# name in /etc/sysctl.d/ and put new settings there.
#
# For more information, see sysctl.conf(5) and sysctl.d(5).
vm.nr_hugepages=512

[root@stone ~]# cat /etc/sysctl.d/k8s.conf 
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

使用 sysctl -p 加载 /etc/sysctl.conf 中的参数(默认)或者指定配置文件中的参数:

[root@stone ~]# sysctl -p
vm.nr_hugepages = 512
[root@stone ~]# sysctl -p /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

使用 sysctl --system 从上到下加载以下配置文件中的参数:

  • /run/sysctl.d/*.conf
  • /etc/sysctl.d/*.conf
  • /usr/local/lib/sysctl.d/*.conf
  • /usr/lib/sysctl.d/*.conf
  • /lib/sysctl.d/*.conf
  • /etc/sysctl.conf
[root@stone ~]# sysctl --system
* Applying /usr/lib/sysctl.d/00-system.conf ...
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
* Applying /usr/lib/sysctl.d/10-default-yama-scope.conf ...
kernel.yama.ptrace_scope = 0
* Applying /usr/lib/sysctl.d/50-default.conf ...
kernel.sysrq = 16
kernel.core_uses_pid = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.promote_secondaries = 1
net.ipv4.conf.all.promote_secondaries = 1
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
* Applying /etc/sysctl.d/99-sysctl.conf ...
vm.nr_hugepages = 512
* Applying /etc/sysctl.d/k8s.conf ...
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
* Applying /etc/sysctl.conf ...
vm.nr_hugepages = 512

资源限制

Linux 可以在文件 /etc/security/limits.conf 中配置用户的资源限制,不要影响在系统服务中配置的资源限制。

[root@stone ~]# cat /etc/security/limits.conf 
# /etc/security/limits.conf
#
#This file sets the resource limits for the users logged in via PAM.
#It does not affect resource limits of the system services.
#
#Also note that configuration files in /etc/security/limits.d directory,
#which are read in alphabetical order, override the settings in this
#file in case the domain is the same or more specific.
#That means for example that setting a limit for wildcard domain here
#can be overriden with a wildcard setting in a config file in the
#subdirectory, but a user specific setting here can be overriden only
#with a user specific setting in the subdirectory.
#
#Each line describes a limit for a user in the form:
#
#<domain>        <type>  <item>  <value>
#
#Where:
#<domain> can be:
#        - a user name
#        - a group name, with @group syntax
#        - the wildcard *, for default entry
#        - the wildcard %, can be also used with %group syntax,
#                 for maxlogin limit
#
#<type> can have the two values:
#        - "soft" for enforcing the soft limits
#        - "hard" for enforcing hard limits
#
#<item> can be one of the following:
#        - core - limits the core file size (KB)
#        - data - max data size (KB)
#        - fsize - maximum filesize (KB)
#        - memlock - max locked-in-memory address space (KB)
#        - nofile - max number of open file descriptors
#        - rss - max resident set size (KB)
#        - stack - max stack size (KB)
#        - cpu - max CPU time (MIN)
#        - nproc - max number of processes
#        - as - address space limit (KB)
#        - maxlogins - max number of logins for this user
#        - maxsyslogins - max number of logins on the system
#        - priority - the priority to run user process with
#        - locks - max number of file locks the user can hold
#        - sigpending - max number of pending signals
#        - msgqueue - max memory used by POSIX message queues (bytes)
#        - nice - max nice priority allowed to raise to values: [-20, 19]
#        - rtprio - max realtime priority
#
#<domain>      <type>  <item>         <value>
#

#*               soft    core            0
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4

# End of file

其中:

  • memlock:可锁定的最大内存,单位 KB
  • nofile:可打开的最大文件数
  • nproc:可启动的最大进程数

如果要调整以上资源限制,可以在该文件最后进行修改,修改完成后重新登录即可生效:

[root@stone ~]# tail -2 /etc/security/limits.conf 
* hard nofile 65535
* soft nofile 65535
oracle soft memlock 60397977
oracle hard memlock 60397977

其中:

  • *:表示针对所有用户配置
  • soft:表示软限制
  • hard:表示硬限制

ulimit

使用 ulimit 命令查看各资源限制。

常用选项有:

  • -a:列出所有限制
  • -l:列出内存限制
  • -n:列出文件限制
  • -u:列出进程限制
[root@stone ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 15632
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 15632
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@stone ~]# ulimit -l
64
[root@stone ~]# ulimit -n
65535
[root@stone ~]# ulimit -u
15632

命令

除了可以使用前面介绍的 pstop 命令查看系统运行情况外,还可以使用以下命令查看系统性能情况。

vmstat

使用 vmstat 命令动态显示系统运行情况。

语法为:

vmstat [options] [delay [count]]

其中:

  • delay:间隔秒数
  • count:显示次数

常用选项有:

  • -s:内存情况
  • -d:磁盘情况

每 2 秒显示一次,显示 5 次系统运行情况:

[root@stone ~]# vmstat 2 5
procs  -----------memory----------  ---swap-- -----io---- -system- ------cpu-----
 r  b   swpd   free   buff  cache    si   so    bi    bo   in   cs us sy  id wa st
 1  0      0 1583448   2132 652900    0    0    14     3  114  256  0  0 100  0  0
 0  0      0 1583424   2132 652900    0    0     0     0  221  496  0  0 100  0  0
 0  0      0 1583424   2132 652900    0    0     0     1  225  502  0  0 100  0  0
 0  0      0 1583424   2132 652900    0    0     0     0  213  481  0  1  99  0  0
 0  0      0 1583424   2132 652900    0    0     0     0  225  494  0  0 100  0  0

其中:

  • procs:表示进程情况,以下两项值越大表示系统越忙

    • r:运行进程数量
    • b:不可被唤醒的进程数量
  • memory:表示内存情况,单位为 KB,包括:

    • swpd:使用的 SWAP 大小
    • free:空闲内存大小
    • buff:Buffer 大小
    • cache:Cache 大小
  • swap:SWAP 使用情况,包括:

    • si:每秒从磁盘读取到 SWAP 数据量
    • so:每秒从 SWAP 写入到磁盘数据量
  • io:磁盘 I/O 情况,包括:

    • bi:每秒从块设备接收到的数据块
    • bo:每秒发送到块设备的数据块
  • system:系统情况,包括:

    • in:每秒中断数
    • cs:每秒上下文切换数
  • cpu:各类型负载占 CPU 百分比,包括:

    • us:非内核进程

    • sy:内核进程

    • id:闲置状态

    • wa:等待 I/O 完成

    • st:虚拟机

查看内存情况:

[root@stone ~]# vmstat -s
      1863000 K total memory
       234096 K used memory
       116996 K active memory
        75892 K inactive memory
      1495856 K free memory
         2108 K buffer memory
       130940 K swap cache
      3145720 K total swap
            0 K used swap
      3145720 K free swap
          226 non-nice user cpu ticks
            0 nice user cpu ticks
          477 system cpu ticks
        75032 idle cpu ticks
          267 IO-wait cpu ticks
            0 IRQ cpu ticks
            3 softirq cpu ticks
            0 stolen cpu ticks
       154978 pages paged in
        12149 pages paged out
            0 pages swapped in
            0 pages swapped out
        50220 interrupts
       199856 CPU context switches
   1691498746 boot time
         1811 forks

查看磁盘情况:

[root@stone ~]# vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
       total merged sectors      ms  total merged sectors      ms    cur    sec
sda     5306      3  251150   10291   1364    113   20544     386      0      5
sdb      181      0   10513     160      4      0    4096       5      0      0
sdc      154      0   10558      25      0      0       0       0      0      0
sdd      154      0   10558      11      0      0       0       0      0      0
sde      142      0    8046      36      0      0       0       0      0      0
sdf      171      0    9078      24      0      0       0       0      0      0
sdg      157      0    8038      29      0      0       0       0      0      0
sr0       18      0    2056     115      0      0       0       0      0      0
dm-0    3000      0  186685    9611   1467      0   16407     474      0      5
dm-1      88      0    4408       8      0      0       0       0      0      0
dm-2      43      0    2072      29      0      0       0       0      0      0
dm-3      43      0    2072       5      0      0       0       0      0      0

iostat

使用 iostat 命令查看 CPU 和磁盘 I/O 情况。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]# yum install sysstat -y

语法:

iostat [options] [ device [...] | ALL ] [ interval [ count ] ]

其中:

  • interval:间隔秒数
  • count:显示次数

常用选项有:

  • -c:显示 CPU 使用情况
  • -d:显示磁盘使用情况
  • -h:以易读的单位显示
  • -p:显示指定磁盘分区使用情况
  • -x:显示扩展信息

每 2 秒显示一次,显示 2 次 CPU 使用情况:

[root@stone ~]# iostat -c 2 2
Linux 3.10.0-1160.el7.x86_64 (stone)    08/08/2023      _x86_64_        (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.21    0.00    0.34    0.15    0.00   99.29

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.00    0.00    0.00    0.00    0.00  100.00

其中:

  • %user:没有修改优先级的用户进程所占 CPU 百分比
  • %nice:修改了优先级的用户进程所占 CPU 百分比
  • %system:内核进程所占 CPU 百分比
  • %iowait:等待 I/O 完成所占 CPU 百分比
  • %steal:虚拟机所占 CPU 百分比
  • %idle:闲置状态

查看磁盘使用情况:

[root@stone ~]# iostat -h -x -p sda 2 2
Linux 3.10.0-1160.el7.x86_64 (stone)    08/08/2023      _x86_64_        (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.17    0.00    0.29    0.13    0.00   99.41

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda
                  0.00     0.07    1.93    0.75    70.78    54.15    93.13     0.01    2.88    3.73    0.68   1.27   0.34
sda1
                  0.00     0.00    0.67    0.01     8.32     0.66    26.78     0.00    0.33    0.31    2.25   0.27   0.02
sda2
                  0.00     0.07    1.26    0.74    61.97    53.49   115.32     0.01    3.75    5.57    0.67   1.66   0.33

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.00    0.00    0.00    0.00    0.00  100.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda
                  0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
sda1
                  0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
sda2
                  0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

其中:

  • rrqm/s:每秒读请求合并次数
  • wrqm/s:每秒写请求合并次数
  • r/s:每秒完成的读次数
  • w/s:每秒完成的写次数
  • rkB/s:每秒读数据量,单位 KB
  • wkB/s:每秒写数据量,单位 KB
  • avgrq-sz:请求的平均扇区数量
  • avgqu-sz:请求的平均队列长度
  • await:请求的平均等待时间,单位毫秒
  • r_await:读请求的平均等待时间,单位毫秒
  • w_await:写请求的平均等待时间,单位毫秒
  • %util:I/O 请求所占百分比

perf

使用 perf 命令分析系统性能,查找性能瓶颈,定位热点代码。

如果系统没有这个命令,使用 YUMopen in new window 进行安装:

[root@stone ~]#  yum install -y perf

语法:

perf [--version] [--help] [OPTIONS] COMMAND [ARGS]

其中,常用的 COMMAND 有:

  • record:记录命令的运行情况到 perf.data 文件。
  • report:读取 perf.data 文件进行分析展示。
  • top:实时显示系统的性能情况。

记录当前系统运行情况:

[root@stone ~]# perf record

查看运行情况:

[root@stone ~]# perf report

实时显示系统性能情况:

[root@stone ~]# perf top

启动

简单来讲,Linux 7 启动包含以下阶段:

  1. BIOS:表示 Basic Input/output System,上电后,BIOS 执行开机自检(POST)来识别、检测和初始化系统硬件,加载主引导记录(MBR)。
  2. MBR:表示 Master Boot Record,是 Linux 引导磁盘的第一个扇区(512 字节)中的信息,用于标识操作系统位于何处和如何定位。在这 512 字节中,引导程序加载器占了 446 字节,接下来的 64 字节为磁盘分区表,最后 2 字节用于校验。MBR 检测可启动的设备,并加载 GRUB2 引导程序到内存中,然后把控制权交给 GRUB2。
  3. GRUB2:表示 Grand Unified Bootloader,在 CentOS 7 中,GRUB2 是默认的引导程序。GRUB2 配置文件为 /boot/grub2/grub.cfg。GRUB2 在 /boot 查找 vmlinuz 内核映像文件,一旦找到,加载到内存中,并提取 initramfs 映像文件内容到内存临时文件系统(tmpfs)中。
  4. KERNEL:搜索 initramfs 映像加载磁盘驱动,挂载根目录并加载其他驱动程序,调用 SYSTEMDopen in new window
  5. SYSTEMD:读取 /etc/systemd/system/default.target 指向的文件,启动各种服务。

img

文件

在启动的 GRUB2 阶段,需要配置文件 /boot/grub2/grub.cfg,不要直接修改该配置文件,由命令 grub2-mkconfig 调用配置文件 /etc/default/grub 及目录 /etc/grub.d 下的模板生成。

[root@stone ~]# cat /etc/default/grub 
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

其中:

  • GRUB_TIMEOUT:在开机选择菜单项的超时时间,超过该时间将使用默认的菜单项来引导对应的操作系统。默认 5 秒。等待过程中,按下任意按键都可以中断等待。
  • GRUB_DEFAULT:默认启动项,saved 表示使用 grub2-set-default 命令以序号(从 0 开始)指定的默认启动项,可以选择的启动项有:
[root@stone ~]# awk -F\' '$1=="menuentry " {print $2}' /etc/grub2.cfg
CentOS Linux (3.10.0-1127.el7.x86_64) 7 (Core)
CentOS Linux (0-rescue-9de1d34c53954b70bea8260cbd106b49) 7 (Core)
  • GRUB_CMDLINE_LINUX:添加到菜单中的内核启动参数。

命令

本节介绍与关机,重启相关的命令。

shutdown

使用 shutdown 命令关闭和重启主机。

语法:

shutdown [OPTIONS...] [TIME] [WALL...]

其中:

  • TIME:为时间字符串,可以是 now 表示立即执行,可以是 hh:mm 表示在指定时间执行,还可以是 +m 表示 m 分钟后执行,默认为 +1

常用选项有:

  • -P:关闭系统并断电,默认
  • -h:关闭系统并断电
  • -r:重启
  • -k:不关机,仅发送消息给登录用户
  • -c:取消关机

立即关机:

[root@stone ~]# shutdown -h now

立即重启:

[root@stone ~]# shutdown -r now

poweroff

使用 poweroff 命令关闭主机。

立即关机:

[root@stone ~]# poweroff 

reboot

使用 reboot 命令重启主机。

立即重启:

[root@stone ~]# reboot 

init

使用 init 命令关闭和重启主机。

立即关机,也就是切换到运行级别 0:

[root@stone ~]# init 0

立即重启,也就是切换到运行级别 6:

[root@stone ~]# init 6

安全

从 CentOS 7 开始,默认使用 firewalldopen in new window 来配置防火墙。

架构

firewalld 分为两层:

  • D-Bus:用于防火墙配置工具的接口。
  • Core:处理配置。

firewalld structure

区域

相较于传统的防火墙管理配置工具,firewalld 支持动态更新技术并加入了区域(zone)的概念。简单来说,区域就是预先准备的防火墙策略集合(策略模板),用户可以根据生产场景选择合适的策略集合,从而实现防火墙策略之间的快速切换。

根据从不受信任到受信任的区域的默认信任级别进行排序,预定于的区域有:

  • drop:任何传入的网络数据包都将被丢弃,没有回复。
  • block:任何传入的网络连接都将被拒绝,IPv4 显示 icmp-host-prohibited,IPv6 显示 icmp6-adm-prohibited
  • public:用于公共区域,仅接受设定的传入连接。默认区域。
  • external:用于启用了 IPv4 伪装的外部网络,仅接受设定的传入连接。
  • dmz:适用于非军事区内可公开访问且对内部网络的访问权限有限的计算机,仅接受设定的传入连接。
  • work:用于工作区域,仅接受设定的传入连接。
  • home:用于家庭区域,仅接受设定的传入连接。
  • internal:用于内部网络,仅接受设定的传入连接。
  • trusted:接受所有网络连接。

服务

在 CentOS 7 中,防火墙服务为 firewalld,默认启动。

[root@stone ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2023-08-09 20:57:08 CST; 4min 34s ago
     Docs: man:firewalld(1)
 Main PID: 791 (firewalld)
   CGroup: /system.slice/firewalld.service
           └─791 /usr/bin/python2 -Es /usr/sbin/firewalld --nofork --nopid

Aug 09 20:57:07 stone systemd[1]: Starting firewalld - dynamic firewall daemon...
Aug 09 20:57:08 stone systemd[1]: Started firewalld - dynamic firewall daemon.
Aug 09 20:57:08 stone firewalld[791]: WARNING: AllowZoneDrifting is enabled. This is considered an insecure configuration option.... it now.
Hint: Some lines were ellipsized, use -l to show in full.

关闭,启动和重启服务器服务:

[root@stone ~]# systemctl stop firewalld
[root@stone ~]# systemctl start firewalld
[root@stone ~]# systemctl restart firewalld

开机禁用和开机启用服务器服务:

[root@stone ~]# systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@stone ~]# systemctl enable firewalld   
Created symlink from /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service to /usr/lib/systemd/system/firewalld.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/firewalld.service to /usr/lib/systemd/system/firewalld.service.

命令

firewall-cmd

使用 firewall-cmd 命令配置防火墙。

常用选项有:

  • --state:防火墙状态
  • --reload:重载防火墙规则,动态添加规则
  • --complete-reload:重载防火墙规则,相当于重启防火墙服务
  • --runtime-to-permanent:将临时设定创建为永久设定
  • --check-config:检查永久设定配置
  • --permanent:永久设定,重启防火墙服务后仍有效
  • --get-default-zon:默认区域
  • --set-default-zone=<zone>:设置默认区域
  • --get-active-zone:当前活动区域
  • --get-zones:预定义区域
  • --get-services:预定于服务
  • --zone=<zone>:指定区域,否则使用默认区域
  • --list-all:列出区域中的配置
  • --list-ports:列出区域中的端口
  • --add-port=<portid>[-<portid>]/<protocol>:为区域添加端口
  • --remove-port=<portid>[-<portid>]/<protocol>:从区域删除端口
  • --query-port=<portid>[-<portid>]/<protocol>:是否开放了指定端口
  • --list-services:列出区域中的服务
  • --add-service=<service>:为区域添加服务
  • --remove-service=<service>:从区域删除服务
  • --query-service=<service>:是否开放了指定服务
  • --list-protocols:列出协议
  • --add-protocol=<protocol>:为区域增加协议
  • --remove-protocol=<protocol>:从区域删除协议
  • --query-protocol=<protocol>:是否开放了指定协议
  • --panic-on:启用应急模式,拒绝所有流量,远程连接会立即断开,只有本地能登陆
  • --panic-off:关闭应急模式
  • --query-panic:是否启用了应急模式

查看防火墙状态:

[root@stone ~]# firewall-cmd --state
running

查看预定义区域:

[root@stone ~]# firewall-cmd --get-zones
block dmz drop external home internal public trusted work

查看当前默认区域:

[root@stone ~]# firewall-cmd --get-default-zone
public

查看当前活动区域:

[root@stone ~]# firewall-cmd --get-active-zones
public
  interfaces: ens33

查看指定区域的配置:

[root@stone ~]# firewall-cmd --zone=public --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens33
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

开放指定区域指定端口,重载防火墙规则再查看:

[root@zabbix ~]# firewall-cmd --zone=public --add-port=80/tcp --permanent   
success

[root@zabbix ~]# firewall-cmd --reload
success

[root@zabbix ~]# firewall-cmd --zone=public --list-ports
80/tcp

[root@zabbix ~]# firewall-cmd --zone=public --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens33
  sources: 
  services: dhcpv6-client ssh
  ports: 80/tcp
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

查看预定义的服务:

[root@zabbix ~]# firewall-cmd --get-services
RH-Satellite-6 RH-Satellite-6-capsule amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kerberos kibana klogin kpasswd kprop kshell ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nfs nfs3 nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster quassel radius redis rpc-bind rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync squid ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-server

查看指定区域开放的服务:

[root@zabbix ~]# firewall-cmd --zone=public --list-services
dhcpv6-client ssh

开放 mysql 服务:

[root@zabbix ~]# firewall-cmd --zone=public --add-service=mysql --permanent       
success

[root@zabbix ~]# firewall-cmd --reload
success

[root@zabbix ~]# firewall-cmd --zone=public --list-services
dhcpv6-client mysql ssh

[root@zabbix ~]# firewall-cmd --zone=public --query-service mysql
yes

[root@zabbix ~]# firewall-cmd --zone=public --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens33
  sources: 
  services: dhcpv6-client mysql ssh
  ports: 80/tcp
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:
上次编辑于:
贡献者: stone,stonebox