封面来源:本文封面来源于网络,如有侵权,请联系删除。

本文参考:【小白入门 通俗易懂】2021 韩顺平 一周学会Linux

1. RPM 与 YUM

1.1 RPM 包的管理

RPM 是用于互联网下载包的打包及安装工具,它包含在某些 Linux 分发版中。它生成具有 .RPM 扩展名的文件。RPM 是 RedHat Package Manager(RedHat 软件包管理工具)的缩写,类似 Windows 的 setup.exe,这一文件格式名称虽然打上了 RedHat 的标志,但理念是通用的。

Linux 的分发版本都有采用(SUSE,RedHat,CentOS 等等),可以算是公认的行业标准了。

rpm 包的简单查询指令:

1
2
3
rpm -qa # 查询所安装的所有 rpm 软件包
rpm -qa | more # 分页查看所安装的所有 rpm 软件包
rpm -qa | grep xx # 查询是否已安装 xx

比如查看当前系统是否安装了 firefox,可以用:rpm -qa | grep firefox

rpm 包名的基本形式

对于一个 rpm 包名 firefox-60.2.2-1.el7.centos.x86_64 而言:

firefox 表示名称,60.2.2-1 表示版本号,el7.centos.x86_64 表示适用的操作系统,这里指 CentOS 7.x 的 64 位操作系统,如果是 i686、i386 则表示 32 位操作系统,noarch 表示通用。

rpm 包其他查询指令

1、查询某软件包是否安装:

1
rpm -q 软件包名 # 比如:rpm -q firefox

2、查询软件包信息:

1
rpm -qi 软件包名 # 比如:rpm -qi firefox

3、查询软件包中的文件:

1
rpm -ql 软件包名 # 比如:rpm -ql firefox

4、查询文件所属的软件包:

1
rpm -qf 文件全路径名

5、卸载 rpm 包:

1
rpm -e RPM包的名称 # 比如:rpm -e firefox

-e 中的 e 表示 erase,[ɪˈreɪs],意为擦除、清除、消去等。

6、安装 rpm 包:

1
rpm -ivh RPM包全路径名称

关于使用的 ivh 的含义:i 表示 install,表示安装;v 表示 verbose,意为提示;h 表示 hash,意为进度条。

卸载 rpm 时的注意要点

1、如果其他软件包依赖于需要被卸载的软件包,卸载时会产生错误信息。

2、如果非要删除被依赖的软件包,可以增加 --nodeps 参数以强制删除,但是不推荐怎么使用。比如:

1
rpm -e --nodeps foo # 强制删除 foo 软件包

1.2 Yum 的使用

Yum 是一个 Shell 前端软件包管理器。基于 RPM 包管理,能够从指定的服务器自动下载 RPM 包并安装,可以自动处理依赖关系,并且一次安装所有依赖的软件包。

yum 的基本指令

1、查询 yum 服务器是否有需要安装的软件:

1
2
3
yum list | grep xx软件列表
# 或者
yum list xx软件名称

2、安装指定的 yum 包:

1
yum install xxx软件名称

比如我们使用 yum 来安装 firefox,最后再卸载它:

1
2
3
4
yum list | grep firefox # 查看 yum 服务器上是否含有 firefox
yum install firefox # 安装 firefox
rpm -q firefox # 查看 firefox 是否被安装
rpm -e firefox # 卸载 firefox

2. 搭建 JavaEE 开发环境

2.1 安装 JDK8

首先前往 Oracle 官网下载 Linux 环境下 JDK 的压缩包(假设下载的压缩包名为 jdk-8u301-linux-x64.tar.gz),然后执行以下指令创建 JDK 压缩包存放目录:

1
mkdir /opt/jdk

通过 Xftp 将本地的 JDK 压缩包上传至 Linux 的 /opt/jdk 目录下,然后依次执行以下指令:

1
2
3
4
5
cd /opt/jdk # 进入存放压缩包的目录
tar -zxvf jdk-8u301-linux-x64.tar.gz # 解压
mkdir /usr/local/java # 创建 jdk 存放目录
mv /opt/jdk/jdk1.8.0_301 /usr/local/java # 将解压后的文件移动到 jdk 存放目录中
vim /etc/profile # 修改文件配置环境变量

进入 vim 编辑环境后,键入 i 进入编辑模式,在文件末尾追加以下内容:

1
2
export JAVA_HOME=/usr/local/java/jdk1.8.0_301
export PATH=$JAVA_HOME/bin:$PATH

然后键入 ESC 退出编辑模式,再键入 :wq 保存并退出 vim 编辑模式。

执行以下命令让配置文件生效:

1
source /etc/profile

然后执行以下命令查看 JDK 是否安装成功:

1
java -version

如果出现以下类似内容表明安装成功:

查看JDK是否安装成功的命令

2.2 安装 Tomcat

与 JDK 的安装类似,需要先下载相应的压缩包(假设下载的压缩包名为 apache-tomcat-10.0.12.tar.gz),再上传至 Linux 并解压,相关命令如下:

1
2
3
4
5
6
mkdir /opt/tomcat # 创建 tomcat 压缩包存放路径
# 上传压缩包至 Linux 环境下
tar -zxvf apache-tomcat-10.0.12.tar.gz # 解压
cd apache-tomcat-10.0.12 # 进入解压后的目录
cd bin # 进入 bin 目录
./startup.sh # 运行 tomcat

如果出现以下类似内容表明 Tomcat 启动成功:

启动Tomcat后的成功信息

除此之外,我们还可以开放 8080 端口,使用 IP地址:8080 的方式访问 Tomcat 首页。如果成功出现以下界面,也表明启动成功:

Tomcat启动后首页

备注: 阿里云 ECS 开放 8080 端口的方式参考《【上篇】Linux 基础》一文中文首配置安全组规则的方式开放 8080 端口。

同时还可以进入 Tomcat 安装目录下的 /webapps/ROOT 目录,在此目录中编写一个 HTML 静态页面,然后可以通过 IP地址:8080/xx.html 的方式进行访问。

2.3 安装 IDEA

安装 IDEA 主要是用于在 Linux 上进行办公,在服务器上我们不需要安装 IDEA。

首先进入以下地址下载 Linux 版本的 IDEA:

https://www.jetbrains.com/idea/download/#section=linux

然后与前面的安装步骤一直:创建存放压缩包的文件夹,解压文件,运行即可。

关于运行 IDEA 不能在远程连接上运行,这样是看不到界面的,需要在有界面的环境下运行,运行方式如下:

1
2
cd bin # 进入 IDEA 安装目录下的 bin 目录
./idea.sh # 运行 IDEA

然后使用方式就和在 Windows 上一样了。

2.4 安装 MySQL 5.7

创建 MySQL 压缩包存放目录并进入这个目录:

1
2
mkdir /opt/mysql
cd /opt/mysql

通过 网络 获取 MySQL 安装包:

1
wget http://dev.mysql.com/get/mysql-5.7.26-1.el7.x86_64.rpm-bundle.tar

由于文件比较大,下载需要一定的时间,请耐心等待。

下载完毕后,对其进行解压:

1
tar -xvf mysql-5.7.26-1.el7.x86_64.rpm-bundle.tar

注意解压指令不要使用 z 选项,因为添加此选项表示通过 gzip 指令处理备份文件,此压缩文件没有 .gz 后缀,因此是不能使用 z 选项的。

CentOS 7.6 会自带一个类 MySQL 数据库 mariadb,它会和 MySQL 冲突,因此需要将其删除。

运行以下指令,查询 mariadb 相关安装包:

1
rpm -qa | grep maria

如果查询内容不为空,需要将相关安装包删除。

我当前的系统存在 mariadb-libs-5.5.68-1.el7.x86_64,因此需要执行以下命令,强制卸载它:

1
rpm -e --nodeps mariadb-libs

卸载之后再执行一次查询命令,看看是否卸载成功。

然后按顺序执行以下命令,进入 MySQL 真正的安装:

1
2
3
4
rpm -ivh mysql-community-common-5.7.26-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-5.7.26-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-5.7.26-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-5.7.26-1.el7.x86_64.rpm

前三条执行都很顺利,但是第四条指令执行后出现以下错误:

安装MySQL缺少libaio

这是因为缺少 libaio 依赖,安装它就行:

1
yum install libaio

安装完成后再次执行安装 MySQL 的第四条指令。

执行完毕后,启动 MySQL:

1
systemctl start mysqld.service

启动完成后并没有任何提示,运行以下指令查看 MySQL 启动状态:

1
systemctl status mysqld.service

如果看到 Active 为 active (running) 就表明启动成功。

MySQL 会自动给 root 用户设置随机密码,运行以下指令可看到初始密码:

1
grep "password" /var/log/mysqld.log

使用以下指令与初始密码登录:

1
mysql -u root -p # 执行指令后输入初始密码

成功登录后要修改初始密码,密码中必须包含大小写字母数字及符号,但对于个人开发设置一个简单的密码就行了,因此可以执行以下语句更改 MySQL 密码验证策略(默认策略是 1):

1
set global validate_password_policy=0;

运行以下语句设置新密码为 12345678:

1
set password for 'root'@'localhost'=password('12345678');

如果上述语句执行失败,可以使用以下语句:

1
ALTER USER 'root'@'localhost' IDENTIFIED BY '12345678';

最后运行以下语句使密码生效:

1
flush privileges;

MySQL 常用命令

1
2
3
4
systemctl start mysqld.service # 开启服务
systemctl stop mysqld.service # 关闭服务
systemctl status mysqld.service # 查看服务状态
mysql -u root -p # 进入命令窗口
1
2
3
4
show databases; # 查看所有数据库
use 数据库名; # 使用该数据进行编辑
show tables; # 查看某数据库所有表
quit; # 退出命令窗口

MySQL 密码验证策略

长度要求(默认 8 位) 数字 字母大小写 特殊字符 字典文件
0 ✔️
1 ✔️ ✔️ ✔️ ✔️
2 ✔️ ✔️ ✔️ ✔️ ✔️

MySQL 密码验证策略有三种,其中 0 密码复杂度最低,2 密码复杂度最高。

2.5 安装 Maven

前面已经安装了好几个软件了,在此就省略下载解压等步骤。Maven 的下载地址可去:Maven 下载地址

当我们加压好 Maven 后,进入 Maven 安装目录下的 conf 目录并修改 settings.xml 文件:

1
2
cd conf
vim settings.xml

在此文件中追加以下内容:

1
2
3
4
5
6
7
8
9
<!-- 设置本地仓库的位置 -->
<localRepository>/usr/local/apache-maven-3.8.1/repository</localRepository>
<!-- 设置下载镜像 -->
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>

追加完毕后保存并退出,接下来修改环境变量:

1
vim /etc/profile # 进入环境变量配置文件

然后在此文件最底部追加以下内容:

1
2
export MAVEN_HOME=/usr/local/maven/apache-maven-3.8.1
export PATH=$PATH:$MAVEN_HOME/bin

其中 MAVEN_HOME 表示 Maven 的安装目录,根据自己的实际进行修改。

追加完毕后保存并退出,执行以下命令让环境变量生效:

1
source /etc/profile

最后执行以下命令,查看 Maven 是否安装成功:

1
mvn -v

3. Shell 编程

3.1 Shell 编程引言

为什么要学习 Shell 编程?

1、Linux 运维工程师在进行服务器集群管理时,需要编写 Shell 程序来进行服务器管理。

2、对于 JavaEE 和 Python 程序员来说,由于工作的需要,你的老大会要求你编写一些 Shell 脚本进行程序或是服务器的维护,比如编写一个定时备份数据库的脚本。

3、对于大数据程序员来说,需要编写 Shell 程序来管理集群。

Shell 是什么

Shell 是一个命令行解释器,它为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序,用户可以用 Shell 来启动、挂起、停止甚至是编写一些程序。

Linux系统结构

3.2 Shell 脚本的执行方式

格式要求

脚本要以 #!/bin/bash 开头。脚本需要有可执行权限。

常用执行方式

方式 1:输入脚本的绝对路径或相对路径执行。在执行之前需要赋予脚本 +x 权限。

方式 2:采用 sh 脚本 的方式运行,这种运行方式无需赋予脚本可执行权限,直接执行即可。

简单案例

创建一个 Shell 脚本,输出“hello world!”。

执行以下命令创建 Shell 脚本,Shell 一般以 .sh 作为后缀名,当然也可以不是:

1
vim hello.sh

在这个脚本中进行如下编码:

1
2
#!/bin/bash
echo "hello world!"

保存并退出 Vim 编辑模式。使用 ll 指令可以看到 hello.sh 并没有执行权限,使用第二种方式执行脚本:

1
sh ./hello.sh

可以成功输出“hello world!”,为 hello.sh 赋予可执行权限:

1
chmod u+x hello.sh

然后使用第一种方式执行脚本:

1
./hello.sh

也可以成功输出“hello world!”。

3.3 Shell 的变量

在 Linux Shell 中的变量分为系统变量和用户自定义变量。

系统变量比如:$HOME$PWD$SHELL$USER 等等。如果需要查看 $HOME 系统变量的值,可以十一 echo $HOME 指令。

显示当前 Shell 中所有的变量使用指令 set 即可。

Shell 自定义变量的定义

定义变量:变量名=值

撤销变量:unset 变量名

声明静态变量:readonly 变量名

注意: 声明变量 =前后不能添加空格!静态变量不能被撤销。

变量声明案例

案例 1:声明变量 A

案例 2:撤销变量 A

案例 3:声明静态变量 B = 2

案例 4:把变量提升为全局环境变量,可供其他 Shell 程序使用

执行 vim var.sh 指令创建 Shell 脚本,在脚本中追加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
# 案例 1:声明变量 A
A=100
echo A=$A # 输出变量时需要使用 $ 符号
echo "A=$A"
# 案例 2:撤销变量 A
unset A
echo "A=$A"
# 案例 3:声明静态变量 B = 2
readonly B=2
echo "B=$B"
# 把指令的返回结果赋值给变量
C=`date`
D=$(date)
echo "C=$C"
echo "D=$D"
# 案例 4:把变量提升为全局环境变量,可供其他 Shell 程序使用
# 在 /etc/profile 文件中定义环境变量,然后在此使用
echo "java_home=$JAVA_HOME"

变量的定义规则

1、变量名称由字母、数组和下划线组成,不能以数字开头;

2、等号两侧不能有空格;

3、变量名称一般习惯大写。

将命令的返回值赋给变量

1、使用反引号。将运行反引号里的命令,并把结果赋值给变量,比如:

1
A=`date`

2、使用 $()。比如:

1
A=$(date)

3.3 环境变量

设置环境变量的基本语法(在 /etc/profile 文件中添加):

1
export 变量名=变量值 # 将 Shell 变量输出为环境变量/全局变量

如果想要让修改后的配置信息立即生效,可以使用:

1
source 配置文件

设置好环境变量后,就可以在不同的 Shell 脚本中使用。

查询环境变量的值可以使用:

1
echo $variableName # 使用 $ + 变量名

应用实例

1、在 /etc/profile 文件中定义 TOMCAT_HOME 环境变量;

2、查看环境变量 TOMCAT_HOME 的值;

3、在另一个 Shell 程序中使用 TOMCAT_HOME;

注意: 在输出 TOMCAT_HOME 环境变量前,需要让其生效,使用 source /etc/profile 指令。

补充:Shell 中的多行注释

多行注释的语法:

1
2
3
:<<!
内容
!

比如:

1
2
3
4
5
6
:<<!
C=`date`
D=$(date)
echo "C=$C"
echo "D=$D"
!

3.4 位置参数变量

当我们执行一个 Shell 脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变量。

比如:./myshell.sh 100 200,这是一个执行 Shell 脚本的命令,可以在 myshell 脚本中获取到参数 100 和 200 的信息。

简单来说:Shell 脚本相当于一个 Java 中的方法,而位置参数变量就是方法的参数。

基本语法

$n(n 为数字,$0 代表命令本身,$1- 9代表第一到第九个参数,十以上的参数需要用大括号,如9 代表第一到第九个参数,十以上的参数需要用大括号,如{10})

$*(这个变量代表命令行中所有的参数,$* 把所有的参数看成一个整体)

$@(这个变量也代表命令行中所有的参数,不过 $@ 把每个参数区分对待)

$#(这个变量代表命令行中所有参数的个数)

使用案例

编写一个 Shell 脚本 position.sh,在脚本中获取到命令行的各个参数信息。

1
vim position.sh # 编写 Shell 脚本

Shell 脚本中的内容如下:

1
2
3
4
5
#!/bin/bash
echo "0=$0 1=$1 2=$2"
echo "所有的参数=$*"
echo "$@"
echo "参数的个数=$#"

赋予脚本可执行权限并执行脚本:

1
2
chmod u+x position.sh # 赋予可执行权限
./position.sh 100 200# 执行脚本

执行结果:

0=./position.sh 1=100 2=200
所有的参数=100 200
100 200
参数的个数=2

3.5 预定义变量

预定义变量是 Shell 设计者事先已经定义好的变量,可以直接在 Shell 脚本中使用。

基本语法

$$(当前进程的进程号,即 PID)
$!(后台运行的最后一个进程的进程号)
$?(最后一次执行的命令的返回状态。如果这个变量值为 0,表明上一个命令正确执行;如果这个变量值为非 0,表明上一个命令执行不正确,至于具体是哪个数,由命令决定)

使用案例

创建一个名为 preVar.sh 的脚本,在此脚本中使用预定义变量。

preVar.sh 脚本中的内容:

1
2
3
4
5
6
#!/bin/bash
echo "当前执行的进程号=$$"
# 以后台的方式运行一个脚本,并获取它的进程号
/root/shcode/position.sh &
echo "最后一个后台方式运行的进程号=$!"
echo "执行的结果是=$?"

当我们为此脚本赋予执行权限并执行后,会“卡住”,这是因为在 Shell 脚本中执行了另一个脚本,使用 Ctrl + C 退出即可。

3.6 运算符

可以使用运算符在 Shell 脚本中进行各种运算操作。其基本语法是:

1、使用 $((运算式))$[运算式]expr m + n

2、注意 expr 运算符之间要有空格,除 + 之外,还有 \* / % 等多种。

应用实例

1、计算 (2+3)*4 的值;

2、求出命令行的两个参数(参数是整数)的和;

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
# 1.计算 (2+3)*4 的值
RES1=$(((2+3)*4))
RES2=$[(2+3)*4] # 推荐使用这种方式
TEMP=`expr 2 + 3` # 需要一步步地计算,运算符之间要有空格,否则会当成一个整体
RES3=`expr $TEMP \* 4` # 注意乘号的书写方式
echo "RES1=$RES1"
echo "RES2=$RES2"
echo "TEMP=$TEMP"
echo "RES3=$RES3"
# 2.求出命令行的两个参数(参数是整数)的和
SUM=$[$1+$2]
echo "参数之和是 $SUM"

赋予执行权限后,使用以下命令执行:

1
./oper.sh 100 200

输出结果:

RES1=20
RES2=20
TEMP=5
RES3=20
参数之和是 300

3.7 条件判断

在 Shell 编程中,条件判断使用 [] 来完成,其基本语法是:

1
if [ condition ]

注意: condition 前后要有空格!

非空返回 true,可以使用 $? 来验证,如果为 0 表示 true,大于 1 表示 false

简单的应用实例

1
2
3
[ mofan ] # 返回 true
[ ] # 返回 false
[ condition ] && echo OK || echo notOK # 条件满足,执行后面的语句

判断语句

1、判断两个字符串是否相等,可以使用 =

2、判断两个整数之间的大小关系,可以使用:

1
2
3
4
5
6
-lt # 小于
-le # 小于等于
-eq # 等于
-gt # 大于
-ge # 大于等于
-ne # 不等于

3、按照文件权限进行判断:

1
2
3
-r # 有读的权限
-w # 有写的权限
-x # 有执行的权限

4、按照文件类型进行判断:

1
2
3
-f # 文件存在并且是一个常规文件
-e # 文件存在
-d # 文件存在并且是一个目录

应用实例

案例 1:“ok” 是否等于 “ok”

案例 2:23 是否大于等于 22

案例 3:/root/shcode/aaa.txt 文件是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
# “ok” 是否等于 “ok”
if [ "ok" = "ok" ]
then
echo "equal"
fi
# 23 是否大于等于 22
if [ 23 -gt 22 ]
then
echo "大于"
fi
# /root/shcode/aaa.txt 文件是否存在
if [ -f /root/shcode/aaa.txt ]
then
echo "存在"
fi

3.8 流程控制之 if

通过前一节的条件判断,我们已经知道了 if 的基本使用,那其基本语法是怎样的呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
if [ condition ]
then
# code
fi

# 或者

if [ condition ]
then
# code
elif [ condition ]
# code
fi

应用案例

编写 ifcase.sh,如果输入的参数大于等于 60,就输出“及格了”,反之输出“不及格”。

1
2
3
4
5
6
7
#!/bin/bash
if [ $1 -ge 60 ]
then
echo "及格了"
else
echo "不及格"
fi

3.9 流程控制之 case

Shell 编程中也有类似于 switch...case 的语法,其基本语法是:

1
2
3
4
5
6
7
8
9
10
11
12
case $VariableName in
"值1")
# 分支 1
;;
"值2")
# 分支 2
;;
# 省略其他分支
*)
# 默认执行的分支
;;
esac

应用实例

当命令行参数是 1 时,输出“周一”,是 2 时,输出“周二”,其他情况输出“other”。

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
*)
echo "other"
;;
esac

3.10 流程控制之 for

基本语法 1:

1
2
3
4
for 变量 in 值1 值2 值3...
do
# code
done

基本语法 2:

1
2
3
4
for ((初始值;循环控制条件;变量变化))
do
# code
done

应用实例

案例 1:打印命令行输入的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
# 打印命令行输入的参数,注意 $* 和 $@ 的区别
# $* 是把输入的参数当成一个整体
for i in "$*"
do
echo "num is $i"
done
# $@ 会把输入的参数当成一个集合,区别对待每一个参数
echo "一条分割线"
for j in "$@"
do
echo "num is $j"
done

执行指令与对应的输出结果:

[root@mofan shcode]# ./testfor1.sh 100 200 300
num is 100 200 300
一条分割线
num is 100
num is 200
num is 300

案例 2:输出显示从 1 到 100 累加的值。

1
2
3
4
5
6
7
#!/bin/bash
SUM=0
for((i=1; i<=100; i++))
do
SUM=$[$SUM+$i]
done
echo "SUM=$SUM" # 输出 5050

3.11 流程控制之 while

除了 for 之外,Shell 编程还支持 while 循环。其基本语法是:

1
2
3
4
while [ condition ]
do
# code
done

应用实例

从命令行输入一个数 n,统计从 1 到 n 的累加值。

1
2
3
4
5
6
7
8
9
#!/bin/bash
i=0
SUM=0
while [ $i -le $1 ]
do
SUM=$[$SUM+$i]
i=$[$i+1]
done
echo "SUM=$SUM"

3.12 读取控制台输入

可参考的教程:Guide to the Linux read Command

使用 read 可以读取控制台的输入,其基本语法是:

1
read [选项] [参数]

read 常用的选项:

选项 含义
-p 指定读取值时的提示符
-t 指定读取值时等待的时间(秒)。如果没在指定时间输入,就不再等待。
-n 后跟一个数字,定义输入文本的长度
-r 屏蔽 \,如果没有该选项,\ 将作为转义字符,反之为正常字符
-e 使用 Bash 内置的 Readline 库读取输入行,添加 -e 参数后能够更好地修改输入错误的内容

应用案例

案例 1:读取控制台输入一个 NUM1 值;

案例 2:读取控制台输入一个 NUM2 值,在 10 秒后输入。

1
2
3
4
5
6
7
#!/bin/bash
# 案例 1
read -p "请输入一个数NUM1= " NUM1
echo "你输入的数NUM1= $NUM1"
# 案例 2
read -t 10 -p "请输入一个数NUM2= " NUM2
echo "你输入的数NUM2= $NUM2"

3.13 系统函数

Shell 编程和其它编程语言一样,有系统函数,也可以自定义函数。在此介绍两个系统函数。

basename

basename 指令可以返回完整路径最后一个 / 的后续部分,常用于获取文件名。比如:

1
2
basename [pathname] [suffix]
basename [string] [suffix] # basename 会删掉所有的前缀包括最后的 /,然后将字符串显示出来

suffix 为后缀,如果 suffix 被指定了,basename 会将 pathname 或 string 中的 suffix 去掉。

应用案例:请返回 /home/aaa/test.txt 的“test.txt”部分。

1
2
basename /home/aaa/test.txt # 输出 test.txt
basename /home/aaa/test.txt .txt # 输出 test

dirname

dirname 可以返回完整路径最后一个 / 的前面部分,常用于返回文件的路径。其基本语法是:

1
dirname 文件绝对路径 # 从给定的包含绝对路径的文件名中去除文件名(非目录的部分) ,然后返回剩下的路径(目录的部分)

应用实例:请返回 /home/aaa/test.txt/home/aaa

1
dirname /home/aaa/test.txt

3.14 自定义函数

自定义函数的基本语法:

1
2
3
4
5
[ function ] funcname[()]
{
Action;
[return int;]
}

调用自定义函数使用:funcname [值]

应用实例

自定义函数 getSum 用于计算两个参数的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
# 自定义函数 getSum
function getSum() {

SUM=$[$n1+$n2]
echo "和是 $SUM"
}

# 输入两个值
read -p "请输入第一个加数 " n1
read -p "请输入第二个加数 " n2

# 调用自定义函数
getSum $n1 $n2

3.15 综合案例

需求分析

1、每天凌晨 2:30 备份数据库 MofanDB 到 /data/backup/db;

2、备份开始和备份结束能够给出相应的提示信息;

3、备份后的文件要求以备份时间为文件名,并打包成 .tar.gz 的形式,比如:2021-03-12_230201.tar.gz;

4、在备份的同时检查是否有 10 天前备份的数据库文件,如果有就将其删除。

前置准备

执行以下命令并输入密码,进入 MySQL 数据库命令行界面:

1
mysql -u root -p

在 MySQL 数据库命令行中依次输入以下命令,完成数据库的创建、数据表的创建和数据的插入:

1
2
3
4
5
6
7
8
SHOW DATABASES; -- 查看数据表信息
CREATE DATABASE IF NOT EXISTS MofanDB; -- 创建数据表
USE MofanDB; -- 使用 MofanDB 数据库
CREATE TABLE tb_student(id INT(16), name VARCHAR(10), age INT(3)); -- 创建表
SHOW TABLES; -- 显示当前库中的表信息
DESC tb_student; -- 查看表结构
INSERT INTO tb_student VALUES(123456789, 'mofan', 19); -- 插入一条数据
SELECT * FROM tb_student; -- 查询数据

脚本编写步骤

执行以下指令进入 sbin 目录并创建 Shell 脚本:

1
2
cd /usr/sbin 
vim mysql_db_backup.sh

然后在 Shell 脚本中编写以下指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash
# 备份目录
BACKUP=/data/backup/db
# 当前时间
DATETIME=$(date +%Y-%m-%d_%H%M%S)
echo $DATETIME
# 数据库地址,就算在阿里云 ECS 上也使用 localhost
HOST=localhost
# 数据库用户名
DB_USER=root
# 数据库密码
DB_PW=12345678
# 备份的数据库名
DATABASE=MofanDB

#创建备份目录,如果不存在就创建
[ ! -d "${BACKUP}/${DATETIME}" ] && mkdir -p "${BACKUP}/${DATETIME}"

# 备份数据库
mysqldump -u${DB_USER} -p${DB_PW} --host=${HOST} -q -R --databases ${DATABASE} | gzip > ${BACKUP}/${DATETIME}/$DATETIME.sql.gz

# 将文件处理成 tar.gz
cd ${BACKUP}
tar -zcvf $DATETIME.tar.gz ${DATETIME}
# 删除对应的备份目录
rm -rf ${BACKUP}/${DATETIME}

# 删除10天前的备份文件
find ${BACKUP} -atime +10 -name "*.tar.gz" -exec rm -rf {} \;
echo "备份数据库 ${DATABASE} 成功"

最后就是要让编写的脚本定时执行即可。

先执行以下指令进入调度文件:

1
crontab -e

在调度文件中追加以下内容,表示每天 2:30 执行备份脚本:

1
30 2 * * * /usr/sbin/mysql_db_backup.sh

然后保存并退出,执行以下指令查看当前任务调度信息中是否有刚刚追加的调度任务:

1
crontab -l

到此,我们的定时备份脚本就写完了。

3.16 字符串截取

参考链接:Shell脚本8种字符串截取方法总结

# 截取,删除左边字符,保留右边字符

1
2
var=http://www.aaa.com/123.htm
echo ${var#*//}

其中 var 是变量名,# 是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符,即删除 http://。最终结果是 www.aaa.com/123.htm

## 截取,删除左边字符,保留右边字符

1
2
var=http://www.aaa.com/123.htm
echo ${var##*/}

##*/ 表示从左边开始删除最后(最右边)一个 / 及左边的所有字符,即删除 http://www.aaa.com/。最终结果是 123.htm

% 截取,删除右边字符,保留左边字符

1
2
var=http://www.aaa.com/123.htm
echo ${var%/*}

%/* 表示从右边开始,删除第一个 / 号及右边的字符。最终结果是:http://www.aaa.com

%% 号截取,删除右边字符,保留左边字符

1
2
var=http://www.aaa.com/123.htm
echo ${var%%/*}

%%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符。最终结果是 http:

从左边第几个字符开始,及字符的个数

1
2
var=http://www.aaa.com/123.htm
echo ${var:0:5}

其中的 0 表示左边第一个字符开始,5 表示字符的总个数。最终结果是:http:

从左边第几个字符开始,一直到结束

1
2
var=http://www.aaa.com/123.htm
echo ${var:7}

其中的 7 表示左边第 8 个字符开始,一直到结束。最终结果是 www.aaa.com/123.htm

从右边第几个字符开始,及字符的个数

1
2
var=http://www.aaa.com/123.htm
echo ${var:0-7:3}

其中的 0-7 表示右边算起第七个字符开始,3 表示字符的个数。最终结果是 123

从右边第几个字符开始,一直到结束

1
2
var=http://www.aaa.com/123.htm
echo ${var:0-7}

表示从右边第 7 个字符开始,一直到结束。最终结果是 123.htm

注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)

3.17 更多参考资料

自己编写 Shell 脚本的机会并不多,相反理解他人的 Shell 脚本含义倒十分常见,以下文章可作为本节补充资料:

4. Ubuntu 的使用

4.1 Ubuntu 的简述

Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的开源 GNU/Linux 操作系统,Ubuntu 是基于 GNU/Linux,支持 x86、amd64 (即 x64)和 PPC 架构,由全球化的专业开发团队(Canonical Ltd)打造的。

专业的 Python 开发者一般会选择 Ubuntu 这款 Linux 系统作为生产平台,因为当 Ubuntu 安装成功后,默认就安装了 Python 环境。

温馨提示:

Ubuntu 和 CentOS 都是基于 GNU/Linux 内核的,因此基本使用和 CentOS 是几乎一样的,它们的各种指令可以通用,在学习和使用 Ubuntu 的过程中,会发现各种操作指令在前面学习 CentOS 都使用过,只是界面和预安装的软件有所差别。

PS:在此省略 Ubuntu 的安装。

4.2 Ubuntu 的中文支持

默认安装的 Ubuntu 中只有英文语言,因此是不能显示汉字的。要正确显示汉字,需要安装中文语言包。

安装中文支持步骤:

1、单击左侧图标栏打开 Language Support 菜单,点击打开 Language Support(语言支持)选项卡。

2、点击 Install/Remove Languages,在弹出的选项卡中下拉找到 Chinese(Simplified),即中文简体,在后面的选项框中打勾。然后点击 Apply Changes 提交变更,系统会自动联网下载中文语言包。(这里需要保证 Ubuntu 是联网的)。

3、这时“汉语(中国)”在最后一位因为当前第一位是“English”,所以默认显示都是英文。如果我们希望默认显示用中文,则应该将“汉语中国)”设置为第一位。设置方法是拖动,鼠标单击“汉语(中国)”,当底色变化(表示选中了)后,按住鼠标左键不松手,向上拖动放置到第一位。

4、设置后不会即刻生效,需要下一次登录时才会生效。

4.3 Ubuntu 的 root

安装 Ubuntu 成功后,都是普通用户权限,并没有最高 root 权限。如果需要使用 root 权限,通常都会在命令前面加上 sudo

我们一般使用 su 指令来直接切换到 root 用户的,但如果没有给 root 设置初始密码,就会出现以下问题:

su: Authentication failure

所以,我们需要给 root 用户设置一个初始密码。

给 root 用户设置密码

1、输入 sudo passwd 指令,输入一般用户密码并设定 root 用户密码。

2、设定 root 密码成功后,输入 su 指令,并输入刚才设定的 root 密码,就可以切换成 root 了。提示符 $ 代一般用户,而提示符 # 代表 root 用户。
3、输入 exit 指令,退出 root 并返回一般用户。

4.4 APT 软件管理

APT 是 Advanced Packaging Tool 的简称,是一款安装包管理工具。 在 Ubuntu下,我们可以使用 apt 指令进行软件包的安装、删除、清理等,类似于 Windows 中的软件管理工具。

APT 相关命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sudo apt-get update # 更新源
sudo apt-get install package # 安装包
sudo apt-get remove package # 删除包

sudo apt-cache search package # 搜索软件包
sudo apt-cache show package # 获取包的相关信息,比如说明、大小、版本等
sudo apt-get install package --reinstall # 重新安装包

sudo apt-get -f install # 修复安装
sudo apt-get remove package --purge # 删除包,包括配置文件等
sudo apt-get build-dep package # 安装相关的编译环境

sudo apt-get upgrade # 更新已安装的包
sudo apt-get dist-upgrade # 升级系统
sudo apt-cache depends package # 了解使用该包依赖哪些包
sudo apt-cache rdepends package # 查看该包被哪些包依赖
sudo apt-get source package # 下载该包的源代码

为了更快地下载需要安装的包,我们需要配置 APT 的下载镜像。

可以先查看 APT 默认的安装服务器地址:

1
cat /etc/apt/sources.list

前往 清华大学开源软件镜像站,然后找到 Ubuntu 镜像使用帮助,复制其中的内容替换 APT 下载源。

注意: 在替换 sources.list 文件时,我们最好备份原文件。

镜像源更换步骤

1、备份 Ubuntu 默认的源地址:

1
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup

2、进入 root 用户:

1
su # 然后输入密码

3、先清空 sources.list 文件:

1
echo '' > /etc/apt/sources.list

4、复制镜像网站的地址,拷贝到 sources.list 文件。

5、最后更新源地址:

1
sudo apt-get update

APT 的简单使用

1
2
3
sudo apt-get remove vim # 删除 vim
sudo apt-get install vim # 安装 vim
sudo apt-cache show vim # 查看 vim 的信息

4.5 远程登录

SSH 为 Secure Shell 的缩写,由 IETF 的网络工作小组(Network Working Group)所制定。SSH 是建立在应用层和传输层基础上的安全协议。

SSH 是目前较可靠、专为远程登录会话和其他网络服务提供安全性的协议,常用于远程登录。几乎所有 UNIX/LInux平台都可运行 SSH。

使用 SSH 服务,需要安装相应的服务器和客户端。客户端和服务器的关系:如果 A 机器想被 B 机器远程控制,那么 A 机器需要安装 SSH 服务器,B 机器需要安装 SSH 客户端。

和 CentOS 不一样,Ubuntu 默认没有安装 SSHD 服务(可以使用 netstat 指令查看),因此我们不能进行远程登录。

1
netstat -nap | more # 查看端口号和协议信息

如果显示没有 netstat 指令,可以执行以下指令进行安装:

1
apt install net-tools # 安装 net-tools

安装 SSH 并使用

执行以下指令安装 SSH 服务器和客户端:

1
sudo apt-get install openssh-server

再执行以下指令启动 SSHD 服务并监听 22 端口:

1
service sshd restart

从一台 Linux 系统远程登录到另一台 Linux 系统

在创建服务器集群时,会使用到该技术。其基本语法是:

1
ssh 用户名@IP

例如:

1
ssh mofan@192.168.200.222

如果使用 SSH 访问时出现错误,可以查看是否有 ~/.ssh/known_ssh 文件,如果存在可以尝试删除该文件来解决。

如果需要登出,可以使用以下指令:

1
2
3
exit 
# 或者
logout

5. 日志管理

5.1 基本介绍

日志文件是重要的系统信息文件,其中记录了许多重要的系统事件,包括用户的登录信息、系统的启动信息、系统的安全信息、邮件相关信息、各种服务相关信息等。

日志对于安全来说也很重要,它记录了系统每天发生的各种事情,通过日志来检查错误发生的原因,或者受到攻击时攻击者留下的痕迹。

简单来说,日志是用来记录重大事件的工具。

/var/log/ 目录是系统日志文件的保存位置:

Linux下日志存放位置

系统常用的日志

日志文件 说明
/var/log/boot.log 系统启动日志
/var/log/cron 与系统定时任务相关的日志
/var/log/cups 打印信息的日志
/var/log/dmesg 系统在开机时内核自检信息,也可以使用 dmesg 指令直接查看内核自检信息。
/var/log/btmp 错误登录的日志。该文件是二进制文件,不能直接使用 vi 查看,而是要使用 lastb 指令查看
/var/log/lasllog 系统中所有用户最后一次的登录时间的日志,该文件是二进制文件,要使用 lastlog 指令查看
/var/log/mailog 邮件信息的日志
/var/log/message 系统重要消息的日志。这个日志文件中会记录 Linux 系统中绝大多数重要信息。如果系统出现问题,首先要检查的应该就是这个日志文件
/var/log/secure 记录验证和授权方面的倍息,只要涉及账户和密码的程序都会记录,比如系统的登录、ssh 的登录、su 切换用户,sudo 授权,甚至添加用户和修改用户密码都会记录在该文件中
/var/log/wtmp 永久记录所有用户的登陆、注销信息,同时记录系统的后动、重启、关机事件。该文件是二进制文件,要使用 last 指令查看
/var/log/ulmp 记录当前已经登录的用户的信息。这个文件会随着用户的登录和注销而不断变化,只记录当前登录用户的信息。这个文件不能用 vi 查着,而要使用 wwhousers 等命令查看

5.2 日志管理服务

CentOS 7.6 日志服务是 rsyslogd,CentOS 6.x 日志服务是 syslogd。rsyslogd 功能更强大。rsyslogd 的使用、日志文件的格式,和 syslogd 服务兼容的。

在 /ect/rsyslog.conf 文件中记录了日志服务管理的日志有哪些。

查询 Linux 中的 rsyslogd 服务是否启动

1
ps aux | grep "rsyslog" | grep -v "grep"

在上述指令中,grep -v 是什么意思呢?-v 可以改变匹配的意义,只选择不匹配的行。因此 grep -v "grep" 就是挑选出不含有 grep 字符串的行。

查询 rsyslogd 服务的自启动状态

1
systemctl list-unit-files | grep rsyslog

rsyslog.conf 配置文件

我们已经知道 /ect/rsyslog.conf 文件的作用是记录了日志服务管理的日志有哪些,除了系统预置的内容外,我们也可以添加自定义内容。

在编辑这个文件是,其格式为:

1
*.* 			存放日志文件

其中第一个 * 表示日志类型,第二个 * 表示日志级别。

日志类型:

日志类型 含义
auth pam 产生的日志
authpriv ssh、ftp 等登录信息的验证信息
cron 时间任务相关
kern 内核
lpr 打印
mail 邮件
mark(syslog)-rsyslog 服务内部的信息,时间标识
news 新闻组
user 用户程序产生的相关信息
uucp unix to unix copy 主机之间相关的通信
local 1-7 自定义的日志设备

日志级别:

日志级别 含义
debug 有调试信息的,日志通信最多
info 一般信息日志,最常用
notice 最具有重要性的普通条件信息
warning 警告级别
err 错误级别,阻止某个功能或模块不能正常工作的信息
crit 严重级别,阻止整个系统或整个软件不能正常工作的信息
alert 需要立刻修改的信息
emerg 内核崩溃等重要信息
nono 什么都不记录

对上述日志级别而言,从上到下级别从低到高,记录信息越来越少。

由日志服务 rsyslogd 记录的日志文件,日志文件的格式包含以下 4 列:

1、事件产生的时间

2、产生事件的服务器的主机名

3、产生事件的服务名或程序名

4、事件的具体信息

5.3 自定义日志服务

在 /etc/rsyslog.conf 中添加一个日志文件 /var/log/mofan.log。当有事件发送时(比如 sshd 服务相关事件),该文件会接收到信息并保存。

编辑 /etc/rsyslog.conf 文件:

1
vim /etc/rsyslog.conf

在此文件中增加以下信息:

1
2
# 增加自定义的日志
*.* /var/log/mofan.log

表示记录所有类型、所有级别的日志信息到 /var/log/mofan.log 文件中。

添加完信息后,保存修改并重启 Linux 系统。

重启完成后,我们执行以下指令,前往日志目录:

1
cd /var/log

在此目录下可以看到我们自定义的日志文件:

自定义日志文件

执行以下指令,查看与 sshd 服务相关的日志内容:

1
cat mofan.log | grep sshd

通过自定义日志服务,可以将我们关心的日志内容记录到指定的日志文件中。

5.4 日志轮替

日志轮替就是把旧的日志文件移动并改名,同时建立新的空日志文件,当旧日志文件超出保存的范围之后,就会进行删除。

日志轮替文件命名

1、CentOS7 使用 logrotate 进行日志轮替管理,要想改变日志轮替文件名字,需要通过修改 /etc/logrotate.conf 配置文件中 dateext 参数。

2、如果配置文件中有 dateext 参数,那么日志会用日期来作为日志文件的后缀,例如 secure-20201010。这样日志文件名不会重复,也不需要日志文件的改名,只需要指定保存日志个数,删除多余的日志文件即可。

3、如果配置文件中没有 dateext 参数,日志文件就需要进行改名了。当第一次进行日志轮替时,当前的 secure 日志会自动改名为 secure.1,然后新建 secure 日志,用来保存新的日志。当第二次进行日志轮替时,secure.1 会自动改名为 secure.2,当前的 secure 日志会自动改名为 secure.1,然后也会新建
secure 日志,用来保存新的日志,以此类推。

/etc/logrotate.conf 文件

/etc/logrotate.conf 文件就是全局的日志轮替策略,也可以单独为某个日志文件指定策略。

也可以把某个日志文件的轮替规则,写到 /etc/iogrotate.d 目录下,在 /etc/logrotate.conf 文件中采用 include 的方式进行加载。

初始 /etc/logrotate.conf 文件内容解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# see "man logrotate" for details
# rotate log files weekly
# 每周对日志文件进行一次轮替
weekly

# keep 4 weeks worth of backlogs
# 共保存 4 份日志文件,当建立新的日志文件时,旧的会被删除
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
# 包含 /etc/logrotate.d 目录下所有的子配置文件,也就是说会把这个目录中所有子配置文件读取出来

# 单独为某个日志文件进行设置,优先级更高
# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
# 每月对日志文件进行一次轮替
monthly
# 创建新的日志文件,权限是 0664,所有者是 root,所属组是 utmp 组
create 0664 root utmp
# 日志文件最小轮替大小是 1M。也就是日志文件大小超过 1M 时才会轮替,否则就算时间到达一个月也不会进行日志转储
minsize 1M
# 仅保留一个日志备份,也就是只有 wtmp 和 wtmp.1 日志保留
rotate 1
}

/var/log/btmp {
# 如果日志不存在,这忽略该日志的警告信息
missingok
monthly
create 0600 root utmp
rotate 1
}

# system-specific logs may be also be configured here.

5.5 自定义日志轮替

logrotate.conf 配置文件参数说明:

参数 说明
daily 日志的轮替周期是每天
weekly 日志的轮替周期是每周
monthly 日志的轮替周期是每月
rotate 数字 保留的日志文件的个数。0 指没有备份
compress 日志轮替时,旧的日志进行压缩
create mode owner group 建立新日志,同时指定新日志的权限与所有者和所属组
mail address 当日志轮替时,输出内容并通过邮件发送到指定的邮件地址
missingok 如果日志不存在,则忽略该日志的警告信息
notifempty 如果日志为空文件,则不进行日志轮替。多用于第一次轮替
minsize 大小 日志轮替的最小值。当日志一定要达到这个最小值才会轮替,否则就算时间达到也不轮替
size 大小 日志只有大于指定大小才进行日志轮替,而不是按照时间轮替
dateext 使用日期作为日志轮替文件的后缀
sharedscripts 在此关键字之后的脚本只执行一次
prerotate/endscripts 在日志轮替之前执行脚本命令
postrotate/endscripts 在日志轮替之后执行脚本命令

把自己的日志加入日志轮替

第一种方法是直接在 /etc/logrotate.conf 配置文件中写入该日志的轮替策略;

第二种方法是在 /etc/logrotate.d/ 目录中新建立该日志的轮替文件,在该轮替文件中写入正确的轮替策略,该目录中的文件都会被 include 到主配置文件中,所以也可以把日志加入轮替。

推荐使用第二种方法,因为系统中需要轮替的日志非常多,如果全都直接写入 /etc/logrotate.conf 配置文件中,那么这个文件的可管理性就会非常差,不利于此文件的维护。

比如在 /etc/logrotate.d/ 目录下创建 mofanlog 轮替文件,在此文件中指定 /var/log/mofan.log 日志文件的轮替策略:

1
2
3
4
5
6
7
8
/var/log/mofan.log
{
missingok
daily
copytruncate
rotate 7
notifempty
}

5.6 日志轮替原理

日志轮替之所以可以在指定的时间备份日志,是依赖系统定时任务。在 /etc/cron.daily/ 目录中会发现有个可执行的 logrotate 文件,日志轮替就是通过这个文件依赖定时任务执行的。

可执行的logrotate文件

5.7 查看内存日志

使用 journalctl 指令可以查看内存日志,以下列举常用的相关指令:

指令 含义
journalctl 查看全部
journalctl -n 3 查看最新 3 条
journalctl --since 19:00 --until 19:10:10 查看起始时间到结束时间的日志可加日期
journalctl -p err 报错日志
journalctl -o verbose 日志详细内容
journalctl _PID= 1245 _COMM=sshd 查看包含这些参数的日志(在详细日志查看)
journalctl | grep sshd 查看包含这些参数的日志(在详细日志查看)

注意: journalctl 查看的是内存日志,重启系统后将会清空。

例如使用以下指令来看看用户登录情况,然后重启系统,再次查询,看看日志有什么变化:

1
journalctl | grep sshd

就像我们前面说的那样,重启系统后,以前的日志将会被清空。

6. 定制自己的 Linux

通过裁剪现有 Linux 系统(在此以 CentOS 7.6 为例),创建属于自己的 Min Linux 小系统,以加深我们对 Linux 的理解。

以下操作均在虚拟机上进行演示。

6.1 Linux 启动流程介绍

1、Linux首先要通过自检,检查硬件设备有没有故障;

2、如果有多块启动盘的话,需要在 BIOS中 选择启动磁盘;

3、启动 MBR 中的 bootloader 引导程序;

4、加载内核文件;

5、执行所有进程的父进程、老祖宗 systemd;

6、进入欢迎界面。

在 Linux 的启动流程中,加载内核文件时的关键文件:

① kernel 文件:vmlinuz-3.10.0-957.el7.x86_ 64
② initrd 文件:initramfs-3.10.0-957.el7.x86_64.img

6.2 制作 Min Linux 思路分析

1、在现有的 Linux 系统(CentOS 7.6)上加一块硬盘 /dev/sdb,在硬盘上分两个分区,一个是 /boot,一个是 /,并将其格式化。需要明确的是,现在加的这个硬盘在现有的 Linux 系统中是 /dev/sdb,但是,当我们把东西全部设置好时,要把这个硬盘拔除,放在新系统上,此时就是 /dev/sda

2、在 /dev/sdb 硬盘上将其打造成独立的 Linux 系统,里面的所有的文件是需要拷贝进去的。

3、作为能独立运行的 Linux 系统,内核是一定不能少的 ,要把内核文件和 initramfs 文件也一起拷到 /dev/sdb上。

4、以上步骤完成,我们的自制 Linux 就完成了,创建一个新的 Linux 虚拟机,将其硬盘指向我们创建的硬盘,启动即可。

具体制作流程参考:定制自己的 Linux(2)

7. Linux 内核源码与升级

7.1 初探 Linux 内核源码

现阶段的 Linux 源码是十分庞大的,因此可以使用 Linux 的 0.01 版本进行阅读,在这个版本下,源码仅有 1w 行。

Linux 源码地址:The Linux Kernel Archives

Linux 0.01 源码阅读技巧

1、Linux 0.01 的阅读需要一定的 C 语言知识;

2、阅读源码前,应知道 Linux 内核源码的整体分布情况。现代的操作系统一般由进程管理、 内存管理、文件系统、驱动程序和网络等组成。Linux 内核源码的各个目录大致与此相对应。

3、在阅读方法或顺序上,有纵向和横向之分。所谓纵向就是跟着程序的执行顺序逐步进行阅读,而横向就是按模块进行阅读。它们经常结合在一起进行。

4、对于 Linux 启动的代码可顺着 Linux 的启动顺序一 步步来阅读;对于像内存管理部分,可以单独拿出来进行阅读分析。实际上这是一个反复的过程,不可能读一遍就理解。

Linux 0.01 源码目录介绍

下载好 Linux 0.01 的源码后,可以看到以下文件或目录:

boot 和系统引导相关的代码
fs	 存放 Linux 支持的文件系统代码
include  存放编译 Linux 核心需要的头文件,比如 asm、linux、sys
init   存放核心初始化代码
kernel 和系统内核相关的源码
lib    存放着库代码
Makefile 用于编译
mm     和内存管理相关的代码
tools  工具代码

init 目录下的 main.c

在 main.c 文件下有这样一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void main(void)
{
// 初始化运行时间
time_init();
// tty 初始化
tty_init();
// 陷阱门(硬件中断向量)初始化
trap_init();
// 调度程序初始化
sched_init();
// 缓冲管理初始化
buffer_init();
// 硬盘初始化
hd_init();
// 所有初始化工作完成后,开启中断
sti();
// 进入用户模式
move_to_user_mode();
if (!fork()) {
init();
}

for(;;) pause();
}

7.2 Linux 内核升级

Linux 内核下载

在联网环境下,使用以下指令可以在 Linux 上下载对应版本的 Linux 内核:

1
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.8.16.tar.gz

下载完成后,执行以下命令进行解压:

1
tar -zxvf linux-5.8.16.tar.gz

Linux 内核升级

假设现在我们的 Linux 系统为 CentOS 7.6,我们需要将其从 7.6 内核升级到 7.8 内核(注意兼容性问题)。

注意: 升级的目标内核并不是随意指定的,需要考虑兼容性问题。

执行以下命令,检测内核版本,显示可升级的内核:

1
yum info kernel -q

使用以下指令查看当前内核版本:

1
uname -a

执行以下指令对内核进行升级:

1
yum update kernel

升级完毕后,执行以下指令查看已经安装的内核:

1
yum list kernel -q

执行上述指令后,可以看到两个内核版本,一个是以前的版本,另一个还是新安装的版本。

如果再次使用 uname -a 查看内核版本,会发现依旧是以前的版本。

这是因为在当前 Linux 中存在两个内核,并且新内核与当前系统下的软件是兼容的。如果重启系统,就需要进行内核选择,在此就可以选择刚刚安装的新内核并进入系统。

8. 备份与恢复

8.1 基本介绍

实体机无法做快照,如果系统出现异常或者数据损坏,后果将十分严重,需要要重转系统,还会造成数据丢失。

所以我们可以使用备份和恢复技术,而 Linux 的备份和恢复很简单,有两种方式:

1、把需要的文件(或分区)用 TAR 打包就行,下次需要恢复的时候,再解压开覆盖即可;

2、使用 dumprestore 指令。

如果 Linux 上没有 dumprestore 指令,需要先执行以下指令进行安装:

1
2
yum -y install dump
yum -y install restore

当我们执行第二条安装指令时,可能会提示以下信息:

Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
No package restore available.
Error: Nothing to do

其实这是在安装 dump 时一并安装了 restore,可以输入 dumprestore 查看是否安装成功。

8.2 使用 dump 完成备份

dump 支持分卷和增量备份(所谓增量备份是指备份上次备份后修改 / 增加过的文件,也称差异备份)。

dump 的基本语法如下:

1
2
dump [-cu] [-123456789] [-f <备份后文件名>] [-T <日期>] [ 目录或文件系统]
dump []-wW

dump 指令常用的选项:

选项 含义
-c 创建新的归档文件,并将由一个或多个文件参数所指定的内容写入归档文件的开头
-0123456789 备份的层级。0 为最完整备份,会备份所有文件。若指定 0 以上的层级,则备份至上一次备份以来修改或新增的文件,到9后,可以再次轮替
-f 备份后文件名 指定备份后文件名
-j 调用 bzlib 库压缩备份文件,也就是将备份后的文件压缩成 bz2 格式,让文件更小
-T 日期 指定开始备份的时间与日期
-u 备份完毕后,在 /etc/dumpdares 中记录备份的文件系统,层级,日期与时间等
-t 指定文件名,若该文件已存在备份文件中,则列出名称
-W 显示需要备份的文件及其最后一次备份的层级、时间、日期
-w 与 -W 类似,但仅显示需要备份的文件

应用案例

应用案例 1: 将 /boot 分区下所有内容备份到 /opt/boot.bak0.bz2 文件中,备份等级为 0。

1
dump -0uj -f /opt/boot.bak0.bz2 /boot

输入上述指令后,出现以下错误信息:

DUMP: You can't update the dumpdates file when dumping a subdirectory
DUMP: The ENTIRE dump is aborted.

当备份为一个独立的文件系统(独立的分区)时,可以使用 -u,如果只是备份目录下的文件时,不支持增量备份,不能使用 -u。我们的阿里云 ECS 上没有 /boot 分区,只有 /boot 目录。因此需要去掉 -u 选项,即:

1
dump -0j -f /opt/boot.bak0.bz2 /boot

应用案例 2: 在 /boot 目录下增加一个新文件,备份层级为 1(只备份上次使用层级 0 备份后发生过改变的数据),并观察这次生成的备份文件 boot1.bak1.bz2 的大小。

1
dump -1uj -f /opt/boot.bak1.bz2 /boot

与案例 1 一样,我们先去掉 -u 选项,即:

1
dump -1j -f /opt/boot.bak1.bz2 /boot

但是出现了其他的错误信息:

DUMP: Only level 0 dumps are allowed on a subdirectory
DUMP: The ENTIRE dump is aborted.

当备份为一个独立的文件系统(独立的分区)时,可以使用多层级备份。如果只是备份目录下的文件时,不支持增量备份,只能使用 -0

所以针对目录下的文件并不能使用增量备份。按照提示信息更改命令:

1
dump -0j -f /opt/boot.bak1.bz2 /boot

除此之外,可以使用 dump 指令再配合 crontab 实现无人值守备份。

拓展: 如果是备份一个独立的文件系统,并执行上述的两条命令,可以观察到第二次备份文件的体积是远小于第一次备份文件的体积的,这是因为第二次备份是增量备份,只备份了相较于第一次备份发生了改变的文件,而这里发生了改变的文件就是新增的那个文件。

其他相关指令

显示需要备份的文件及其最后一次备份的层级、时间和日期:

1
dump -W

查看备份时间文件:

1
cat /etc/dumpdates

8.3 使用 restore 完成恢复

restore 命令可以用来恢复已备份的文件,可以从 dump 指令生成的备份文件中恢复原文件。

restore 的基本语法如下:

1
restore [模式选项] [选项]

restore 指令的四种模式如下,它们不能混用,在一次命令中,只能指定一种:

模式选项 含义
-C 使用对比模式,将备份的文件与已存在的文件相互对比
-i 使用交互模式,在进行还原操作时,restore 指令将依序询问用户
-r 进行还原模式
-t 查看模式,看备份文件有哪些文件

restore 指令常用的选项:

选项 含义
-f 备份设备 从指定的文件中读取备份数据,进行还原操作

应用案例

应用案例 1: 使用 restore 指令的比较模式,比较备份文件与原文件的区别。

使用的备份文件是前文产生的 /opt/boot.bak1.bz2 文件,先将 /boot/hello.txt 改名为 /boot/hello1.txt:

1
mv /boot/hello.txt /boot/hello1.txt

然后使用 restore 指令的比较模式:

1
restore -C -f /opt/boot.bak1.bz2

指令执行后,会提示这样一段文字,表示备份前后文件发生了变化:

restore: unable to stat ./boot/hello.txt: No such file or directory
Some files were modified! 

那如果再把文件名改回去呢?

1
2
mv /boot/hello1.txt /boot/hello.txt
restore -C -f /opt/boot.bak1.bz2

这时就不会提示某些文件被修改了。

应用案例 2: 使用 restore 指令的查看模式,查看备份文件有哪些数据或文件。

1
restore -t -f /opt/boot.bak1.bz2

应用案例 3: 使用 restore 指令的还原模式。如果进行了增量备份,需要把增量备份文件也进行恢复,有几个增量备份文件就要恢复几个,按顺序依次恢复即可。

假设有一个全量备份文件 /opt/boot.bak0.bz2,还有一个增量备份文件 /opt/boot.bak1.bz2,现在需要将它们恢复到 /opt/boottmp 目录下,则执行以下指令:

1
2
3
4
mkdir /opt/boottmp
cd /opt/boottmp
restore -r -f /opt/boot.bak0.bz2 # 恢复到第1次完全备份状态
restore -r -f /opt/boot.bak1.bz2 # 恢复到第2次增量备份状态

9. Linux 可视化管理工具

9.1 Webmin 的安装和配置

Webmin 的安装

Webmin 是功能强大的基于 Web 的 Unix/Linux 系统管理工具。管理员通过浏览器访问 Webmin 的各种管理功能并完成相应的管理操作。除了各版本的 Linux 外还可用于 AIX、HPUX、Solaris、Unixware、Irix 和 FreeBSD 等系统。

Webmin 的下载地址:下载地址

也可以在 Linux 下使用以下指令进行下载:

1
wget http://download.webmin.com/download/yum/webmin-1.700-1.noarch.rpm

下载完成后,再进行安装:

1
rpm -ivh webmin-1.700-1.noarch.rpm

安装完成后进行重置密码:

1
/usr/libexec/webmin/changepass.pl /etc/webmin root test

上述指令中的 root 是 webmin 的用户名,不是 Linux 操作系统的的,这里就是把 webmin 的 root 用户密码改成了 test。如果出现以下字样,表示密码修改成功:

Updated password of Webmin user root

出于安全目的,建议修改 webmin 服务的端口号(默认端口号是 10000):

1
vim /etc/webmin/miniserv.conf # 修改端口

然后将文件中的 port=10000 修改为其他端口号,比如 port= 6666。修改的地方有两处,一处是 port,另一处是 listen。比如:

1
2
port=6666
listen=6666

再重启 Webmin:

1
2
3
/etc/webmin/restart # 重启
/etc/webmin/start # 启动
/etc/webmin/stop # 停止

还需要使防火墙开放 6666 端口:

1
2
3
firewall-cmd --zone=public --add-port=6666/tcp --permanent # 配置防火墙开放6666端口
firewall-cmd --reload # 更新防火墙配置
firewall-cmd --zone=public --list-ports # 查看已经开放的端口号

由于我们使用的是阿里云 ECS,因此需要配置安全组规则,开放 6666 端口。

最后使用 root 账号和重置的新密码 test 登录在 http://ip:6666 地址上登录 Webmin 即可。如:

登录Webmin

9.2 Webmin 的基本使用

修改界面语言为简体中文

成功登录进 Webmin 后,点击左侧菜单栏中的 Webmin,然后点击 Webmin Configuration,在界面上找到 Language 并点击进入。进入后在 Display in language 处选择 Simplified Chinese (ZH_CN.UTF-8),最后点击按钮 Change Language 完成界面语言的修改。

Webmin界面语言设置

修改后可能不会立即生效,刷新页面即可。

其他操作

1、在左侧菜单栏点击 Webmin,点击 Webmin 配置,选择 IP 控制访问,可以在此对 Webmin 服务器配置为禁止访问或只允许某些 IP 地址访问;

2、在左侧菜单栏点击系统,点击 Change Passwords,可以在此页面选择用户并修改选择用户的密码;

3、在左侧菜单栏点击系统,点击 Cron 任务调度,可以在此页面配置任务调度;

4、在左侧菜单栏点击系统,点击进程管理器,可以在此页面查看当前系统的进程信息;

5、在左侧菜单栏点击服务器,点击 MySQL 数据库服务器,输入用户名和密码后,可以进行数据库的可视化管理(当然记得先开启 MySQL 服务)。

其余操作不再一一列举…

9.3 宝塔的介绍与安装

BT 宝塔 Linux 面板是提升运维效率的服务器管理软件,支持一键 LAMP/LNMP/集群/监控/网站/FTP/数据库
/Java 等多项服务器管理功能。

安装和使用

执行以下指令进行安装:

1
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh

上述指令中 && 表示左侧的指令成功执行后才会去执行右侧的指令。

执行命令后,如果出现以下字样,表示宝塔面板安装成功:

Congratulations! Installed successfully!

安装成功后控制台会显示外网(或内网)登录地址和账户密码,复制外网(或内网)地址在浏览器打开并登录。

宝塔面板的访问会需要使用到 8888 端口,若无法访问面板,请检查防火墙 / 安全组是否有放行面板 8888 端口。

我成功进入宝塔面板后,弹出这样一个对话框:

恶心的绑定宝塔账号

What the Fxxk?

这个对话框还无法关闭,强制要求绑定或注册宝塔账号,国产软件就这个尿性,不绑定就不给用,那就不用呗。

宝塔的卸载

既然不用它了,自然得把它写了,执行以下命令卸载宝塔:

1
/etc/init.d/bt stop && rm -f /etc/init.d/bt && rm -rf /www/server/panel

或者更暴力一点,依次执行以下命令进行卸载:

1
2
wget http://download.bt.cn/install/bt-uninstall.sh
sh bt-uninstall.sh

虽然卸载了面板以及面板环境,可是系统还是会残留一些文件的,比如在根目录下的 www 目录,执行以下命令再次进行删除:

1
rm –rf  /www

结果执行后出现以下信息:

rm: cannot remove ‘/www/swap’: Operation not permitted

执行以下指令,去除 i 属性:

1
chattr -i www

然后再执行删除命令即可。

10. Linux 面试题

10.1 腾讯面试题

分析日志 t.log(访问量),将各个 IP 地址截取,并统计出现的次数,最后按从大到小排序。

日志 t.log 内容如下:

http://192.168.200.10/index1.html
http://192.168.200.10/index2.html
http://192.168.200.20/index1.html
http://192.168.200.30/index1.html
http://192.168.200.40/index1.html
http://192.168.200.30/order.html
http://192.168.200.10/order.html
1
cat t.log | cut -d '/' -f 3 | sort | uniq -c | sort -nr

uniq -c 指令是统计相邻行的重复情况,所以要先使用 sort 排序,将相同的 IP 排在一起然后才能统计。

统计连接到服务器的各个 IP 情况,并按连接数从大到小排序。

1
netstat -an | grep ESTABLISHED | awk -F " " '{print $5}' | awk -F ":" '{print $1}' | sort | uniq -c | sort -nr

或者:

1
netstat -an | grep ESTABLISHED | awk -F " " '{print $5}' | cut -d ":" -f 1 | sort | uniq -c | sort -nr

cut 指令不支持以空格分割,所以需要使用 awk 指令进行空格分析。

假如你是系统管理员,在进行 Linux 系统权限划分时,应当考虑那些因素?

1、首先阐述 Linux 权限的主要对象

Linux权限一图流

2、根据自己的实际经验谈考虑因素,如:

  • 注意权限分离。比如工作中,Linux 系统权限和数据库权限不要在同一一个部门;

  • 权限最小原则,即在满足使用的情况下最少优先;

  • 减少使用 root 用户,尽量用普通用户 + sudo 提权进行日常操作;

  • 重要的系统文件,比如 /etc/passwd、/etc/shadow、etc/fstab、/etc/sudoers 等,日常建议使用 chattr锁定,需要操作时再打开。

  • 使用 SUID、SGID、Sticky 设置特殊权限;

  • 可以利用工具,比如 chkrootkit 或 rootkit hunter 检测 rootkit 脚本(rootkit 是入侵者使用工具,在不察觉的建立了入侵系统途径);

  • 利用工具 Tripwire 检测文件系统完整性;

说明 CentOS 7 的启动流程,并说明与 CentOS 6 的差异。

参考视频:CentOS 7 启动流程详解

运维细看,Java 开发略过即可。

补充:文件的锁定

对于文件的锁定,比如对 /ect/password 进行锁定让任何用户都不能随意useradd,除非解除锁定,执行指令 chattr +i /etc/passwd即可。但是这样不够安全,其他人也可以通过以下指令解除权限:

1
chattr -i /etc/passwd

对此可以移动下 chattr 指令的位置:

1
mv /usr/bin/chattr /opt

但是其他人可以通过以下指令搜索到 chattr 指令的位置:

1
find / -name chattr

对此可以修改 chattr 指令:

1
mv /opt/chattr /opt/h

补充:chkrootkit 的使用

参考链接:Linux下rootkit后门检测工具chkrootkit安装使用

安装编译工具包:

1
2
yum install gcc gcc-c++ make
yum install glibc-static

目录切换并创建目录:

1
2
cd /opt
mkdir chkrootkit

执行以下指令对工具进行下载:

1
wget ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz

解压:

1
2
3
4
tar zxvf chkrootkit.tar.gz # 解压
cd chkrootkit-0.52
make sense # 安装
mv /usr/local/src/chkrootkit-0.52 /usr/local/chkrootkit # 拷贝到安装目录

使用 chkrootkit:

1
2
cd /usr/local/chkrootkit # 目录切换
./chkrootkit | grep INFECTED # 出现 INFECTED 就说明系统可能有问题了

在 CentOS 7.x 可能会出现下面的提示:

chkrootkit: can't find `netstat'.

原因是系统默认缺少 netstat 命令,进行安装即可:

1
2
yum whatprovides *netstat # 查看命令所在的安装包
yum install net-snmp-utils net-tools # 安装netstat命令即可

10.2 滴滴面试题

如果忘记了 MySQL 5.7 数据库的 root 用户的密码,应该如何找回?

先编辑 /etc/my.cnf 文件:

1
vim /etc/my.cnf

在此文件中追加以下内容:

1
skip-grant-tables

重启 MySQL 服务:

1
service mysqld restart

重启成功后,以空密码访问 MySQL:

1
mysql -u root -p
1
2
3
4
5
6
7
show databases; -- 查看数据库
use mysql;
show tables; -- 查看 mysql 库内的表信息
desc user; -- 查看字段信息
update user set authentication_string=password("123456") where user='root'; -- 密码修改
flush privileges; -- 权限刷新
exit; -- 退出 MySQL

然后再次编辑 /etc/my.cnf,注释或删除开始追加的内容 skip-grant-tables,然后再重启 MySQL 服务,重启后执行:

1
mysql -u root -p

如果还以空密码进入 MySQL 是会被访问拒绝的,需要使用刚刚重置的密码进入。

列出你了解的 Web 服务器负载架构。

1
2
3
4
Nginx
Haproxy
Keepalived
LVS

每天晚上 10 点 30 分,打包站点目录 /var/spool/mail 备份到 /home 目录下(每次备份按时间生成不同的备份包)。

mail.sh Shell 脚本内容:

1
2
#!/bin/bash
cd /var/spool/ && /bin/tar zcf /home/mail-`date +%Y-%m-%d_%H%M%S`.tar.gz

为 mail.sh 增加执行权限并尝试运行:

1
2
chmod u+x mail.sh # 增加执行权限
./mail.sh # 尝试运行

定时执行 mail.sh 脚本:

1
crontab -e

内容追加:

1
30 22 * * * /root/mail.sh

10.3 美团面试题

统计 IP 访问情况,并分析 nginx 访问日志(access.log),找出访问页面数量在前 2 位的 IP

日志 access.log 的内容如下:

192.168.130.21	aaa.html
192.168.130.20	aaa.htmL
192.168.130.20	aaa.html
192.168.130.20  aaa.htmL
192.168.130.23  aaa.html
192.168.130.20  aaa.html
192.168.130.25  aaa.html
192.168.130.20  aaa.html
192.168.130.20  aaa.html
192.168.130.25  aaa.html
192.168.130.20  aaa.html
1
cat access.log | awk -F " " '{print $1}' | sort | uniq -c | sort -nr | head -2 

使用 tcpdump 监听本机,将来自 IP 为 192.168.200.1,TCP 端口为 22 的数据保存输出到tcpdump.log 以便将来数据分析

1
tcpdump -i ens33 host 192.168.200.1 and port 22 >> /opt/interview/tcpdump.log

使用 Linux 命令计算 t2.txt 第二列的和并输出。

t2.txt 的内容如下:

张三 40
李四 50
王五 60
1
cat t2.txt | awk -F " " '{sum+=$2} END {print sum}'

10.4 百度面试题

列举至少 6 个 Linux 高级命令。(百度)

1
2
3
4
5
6
7
netstat # 网络状态监控
top # 系统运行状态
lsblk # 查看硬盘分区
find # 查找
ps -aux # 查看运行进程
chkconfig # 查看服务启动状态
systemctl # 管理系统服务器

Shell 脚本里如何检查一个文件是否存在并给出提示。

1
if [ -f 文件名 ] then echo "存在" else echo "不存在" fi

编写一个 Shell 脚本,对文本 t3.txt 中无序的一列数字进行排序,并输出总和。

1
sort -nr t3.txt | awk '{sum+=$0; print $0} END {print "和="sum}'

$0 表示的是取整个部分;$1 表示的是取分割后的第一部分。这次没有用 -F 指定分割,所以用$0

10.5 其他大厂面试题

常用的 Nginx 模块有哪些?它们的作用是什么?(滴滴)

rewrite 模块用于重写功能;

access 模块用于来源控制;

ssl 模块用于安全加密;

ngx_http_ gzip_ module模块 用于网络传输压缩;

ngx_http_proxy_module 模块实现代理;

ngx_ http_upstream_module 模块实现定义后端服务器列表;

ngx_ cache_purge 模块实现缓存清除功能;

Linux 查看内存、IO 读写、磁盘存储、端口占用、进程查看的命令是什么?(瓜子)

1
2
3
4
5
6
7
8
9
10
top # 查看内存使用情况

yum install iotop # 安装 iotop
iotop # 查看磁盘 IO 读写情况

df -lh # 磁盘存储

netstat -tunlp # 端口占用

ps -aux | grep sshd # 查看 sshd 的进程

请用指令写出查找当前文件夹(/home)下所有的文本文件内容中包含有字符 cat 的文件名称。(金山)

1
grep -r "cat" /home | cut -d ":" -f 1

请写出统计 /home 目录下所有文件个数和所有文件总行数的指令。(金山面试题拓展)

1
find /home -name "*.*" | xargs wc -l

10.6 权限操作思考题

用户 tom 对目录 /home/test 有执行 x 和读写 rw 权限,/home/test/hello.java 是只读文件,问 tom 对 hello.java 文件能读吗?能修改吗?能删除吗?

可读,不可修改(不可修改内容,可修改名称),可删除。

用户 tom 对目录 /home/test 只有读写权限,/home/test/hello.java 是只读文件,问 tom 对 hello.java 文件能读吗?能修改吗?能删除吗?

不可读、修改和删除。

用户 tom 对目录 /home/test 只有执行权限,/home/test/hello.java 是只读文件,问 tom 对 hello.java 文件能读吗?能修改吗?能删除吗?

可读,不可修改和删除。

用户 tom 对目录 /home/test 只有执行和写权限,/home/test/hello.java 是只读文件,问 tom 对 hello.java 文件能读吗?能修改吗?能删除吗?

可读,不可修改,可删除。

10.7 优化 Linux 系统

此为瓜子的一道面试题:如何优化 Linux 系统,说说你的方法。

对 Linux 系统本身的优化

1、不要 root,使用 sudo 提示权限;

2、定时指定更新服务时间,使用 nptdate npt1.aliyun.com 指令,并使用 croud 定时更新;

3、配置 yum 源指向国内镜像(清华、163 等)

4、配置合理的防火墙策略,打开必要的端口,关闭不必要的端口;

5、打开最大文件数(调整文件的描述数量):

1
vim /etc/profile # 修改文件

追加内容:

1
ulimit -SHn 65535

6、配置合理的监控策略;

7、配置合理的系统重要文件的备份策略;

8、对安装的软件进行优化,比如 Nginx、Apache Tomcat 等;

9、对内核参数进行优化(/etc/sysctl.conf);

10、锁定(使用 chattr 指令)一些重要的系统文件;

11、禁用不必要的服务(使用 setupntsysv 指令);

11. 常用指令与补充

11.1 常用指令实践

章节参考:最快Linux入门教程+最新学习路线!程序员必备组合拳

1、连接远程服务器:

1
ssh IP地址

2、查看当前所在目录位置:

1
pwd

3、查看网络设备信息:

1
ifconfig # 或者 ip addr(推荐后者)

4、查看服务器下的内存:

1
free

5、查看磁盘空间:

1
df -lh

6、新建 code 目录:

1
mkdir code

7、切换至 code 目录:

1
cd code/

8、拉取项目代码:

1
git clone xxx

9、进入项目目录:

1
cd xxx

10、查看项目文件:

1
ls

11、查看项目各文件大小:

1
du -sh *

12、查看项目介绍文件:

1
cat README.md

13、查看系统版本:

1
uname -a

14、安装 Java8:

1
yum install java-1.8.0-openjdk* -y

15、查看 Java 版本号:

1
java -version

16、查看 java 命令的位置:

1
which java

17、下载 Maven 压缩包:

1
wget Maven安装包镜像地址

18、解压:

1
tar -zxvf apache-maven-3.8.2-bin.tar.gz

19、项目构建:

1
./apache-maven-3.8.2/bin/mvn install

20、查看构建后项目的 jar 包:

1
find -name '*.jar'

21、移动 jar 包至上级目录:

1
cp ./target/xxx.jar ./

22、jar 包改名:

1
mv xxx.jar code-nav.jar

23、运行 jar 包:

1
java -jar code-nav.jar

24、后台启动程序:

1
nohup java -jar code-nav.jar &

25、查看当前任务:

1
jobs

26、查看进程:

1
ps -ef

27、筛选 java 进程:

1
ps -ef | grep 'java'

28、查看端口占用:

1
netstat -ntlp

29、访问项目:

1
curl localhost:8082/dog

30、切换至日志目录并查看日志:

1
2
3
cd logs/
ls
cat error.log

31、查看最新 10 行日志:

1
tail -n 10 error.log

32、下载日志到本地:

1
sz error.log

33、使用 vim 修改代码:

1
vim pom.xml

34、杀死老进程:

1
kill -9 %l

35、重新构建项目并执行;

36、查看系统中各个进程的资源占用情况:

1
top

37、编写 Shell 脚本;

38、为脚本添加可执行权限:

1
chmod a+x xxx.sh

39、查看历史命令:

1
history

11.2 指令的别名

查看系统默认设置的别名:

1
alias

新增别名:

1
2
# 设置 `ls -lt` 指令的别名为 llt,后续使用 llt 就能达到 ls -lt 的效果
alias llt='ls -lt'

删除别名:

1
unalias llt

指令的别名属于内部指令,一个别名只会在它被定义的 shell 进程中有效,如果想要使其永久生效,可以把别名添加到 Linux 启动文件 .bashrc.bash_profile 中,然后重启系统:

1
2
3
4
# 当前用户生效
echo 'alias llt='ls -lt'' >> ~/.bashrc
# 所有用户生效
echo 'alias llt='ls -lt'' >> /etc/bashrc

因此要删除系统默认设置的别名,不仅要使用 unalias 移除别名,还要在启动文件中删除对应的信息。

11.3 查看日志

显示 file 文件中匹配 foo 字符串那行以及上下 5 行:

1
grep -C 5 foo file

显示 foo 及前 5 行:

1
grep -B 5 foo file

显示 foo 及后 5 行:

1
grep -A 5 foo file

11.4 安全地擦除磁盘数据

11.5 排查 Java 进程导致 CPU 飙升

  1. 使用 top 命令查看 CPU 占用情况,找到占用较高的进程 PID;

  2. 使用以下命令查看对应 PID 的进程及其所有线程的 CPU 使用情况,找到占用较高的线程 ID:

    1
    top -Hp PID
  3. 使用以下命令将对应线程 ID 转换成十六进制:

    1
    printf "%x\n" [线程 ID]
  4. 使用 JDK 自带的 jstack 命令获取 Java 进程的线程快照并输入到 jstack_result.txt 文件中:

    1
    jstack -l [进程 PID] > ./jstack_result.txt
  5. jstack_result.txt 文件中按先前得到的十六进制线程 ID 进行搜索,查看阻塞原因:

    1
    cat jstack_result.txt | grep -A 100 [十六进制线程 ID]