Linux学习03
Shell编程
Shell是什么
Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。d&kF%Nfti3s-
Shell脚本的执行方式
脚本格式要求
1.脚本以#!bin/bash开头(表明以bashell执行)
2.脚本需要有可执行权限
3.shell脚本一般以.sh结尾。虽然也可以以别的结尾,但是一般约定俗成以.sh结尾。
脚本的常用执行方式
编写第一个Shell脚本
需求说明:创建一个Shell脚本,输出hello,world~
方式1(输入脚本的绝对路径或相对路径)
说明:首先要赋予helloworld.sh脚本的+x权限,再执行脚本
1 | mkdir /root/shcode # 创建shcode目录,用于存放后续的shell脚本 |
方法2(sh+脚本)
说明:不用赋予脚本+x权限,直接执行即可。
1 | chmod u-x hello.sh # 去掉执行权限 |
Shell的变量
Shell变量介绍
1.Linux Shell中的变量分为:系统变量和用户自定义变量
2.系统变量:$HOME, $PWD, $SHELL, $USER等等,比如:echo $HOME等等。
3.显示当前shell中所有变量:set
shell变量的定义
基本语法
1.定义变量:变量名=值(不要打空格)
2.撤销变量:unset 变量
3.声明静态变量:readonly 变量,注意:不能unset
快速入门
案例1:定义变量A
案例2:撤销变量A
案例3:声明静态的变量B=2,不能unset(静态变量不会被反复定义和初始化,只会被定义一次)
案例4:可把变量提升为全局环境变量,可供其他shell程序使用
1 |
|
shell变量的命名和赋值规则
定义变量的规则
1.变量名称可以由字母、数字和下划线组成,但是不能以数字开头。
5A=200(不可以)
2.等号两侧不能有空格。
3.变量名称一般习惯为大写
将命令的返回值赋给变量
1.A=``反引号,运行里面的命令,并把结果返回给变量A(没有反引号,会认为是单词赋给A)
2.A=$(date)等价于反引号
设置环境变量
基本语法
1.export 变量名=变量值(功能描述:将shell变量输出为环境变量/全局变量)
2.source 配置文件 (功能描述:让修改后的配置信息立即生效)
3.echo $变量名 (功能描述:查询环境变量的值)
快速入门
1.在/etc/profile文件中定义TOMCAT_HOME环境变量
2.查看环境变量TOMCAT_HOME的值
3.在另外一个shell程序中使用TOMCAT_HOME
1 | vim /etc/profile |
注意:在输出TOMCAT_HOME环境变量前,需要让其生效source/etc/profile
补充:shell脚本的多行注释
1 | :<<! |
位置参数变量
当我们执行一个shell脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变量
比如:./myshell.sh 100 200,这个就是一个执行shell的命令行,可以在myshell脚本中获取到参数信息
基本语法

案例
案例:编写一个shell脚本myshell.sh,在脚本中获取到命令行的各个参数信息。
1 |
|
预定义变量
就是shell设计者事先已经定义好的变量,可以直接在shell脚本中使用
基本语法
$$ (功能描述:当前进程的进程号(PID))
$! (功能描述:后台运行的最后一个进程的进程号(PID))
$? (功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)
应用实例:
在一个shell脚本中简单使用一下预定义变量preVar.sh
1 |
|
运算符
基本语法

应用实例oper.sh
案例1:计算(2+3)*4的值
案例2:请求出命令行两个参数[整数]的和,比如20和50
1 |
|
条件判断
基本语法
1 | if [ condition ] # 注意condition前后要有空格 |
#非空返回true,可使用$?验证(0为true,>1为false)
应用实例
[ Edu ] # 非空,返回true
[ ] # 返回false,中间一定要有空格
[ condition ] && echo OK || echo notok 条件满足,执行后面的语句
常用判断条件
1)=字符串比较
2)两个整数的比较
-lt 小于
-le 小于等于
-eq 等于
-gt 大于
-ge 大于等于
-ne 不等于
3)按照文件权限进行判断
-r 有读的权限
-w 有写的权限
-x 有执行的权限
4)按照文件类型进行判断
-f 文件存在并且是一个常规的文件
-e 文件存在
-d 文件存在并是一个目录
应用实例
案例1:“ok”是否等于“ok”
判断语句:使用 =
案例2:23是否大于等于22
判断语句:使用 -ge
案例3:/root/shcode/aaa.txt目录中的文件是否存在
判断语句:使用 -f
1 |
|
流程控制
if判断
1 | if [ 条件判断式 ] |
多分支-if判断
1 | if [ 条件判断式 ] |
注意事项:[ 条件判断式 ],中括号和条件判断式之间必须有空格
应用实例ifCase.sh
案例:请编写要给shell程序,如果输入的参数,大于等于60,则输出“及格了”,如果小于60,则输出”不及格“
1 |
|
case语句
基本语法
1 | case $变量名 in |
应用实例 testCase.sh
案例1:当命令行参数是1时,输出“周一”,是2时,就输出“周二”,其他情况输出“other”
1 |
|
for循环
基本语法1
1 | for 变量 in 值1 值2 值3... # 值外面可以加双引号 |
应用实例testFor1.sh
案例1:打印命令行输入的参数[这里可以看出$*和$@的区别]
1 |
|
基本语法2
1 | for((初始值;循环控制条件;变量变化)) |
应用实例testFor2.sh
案例1:从1加到100的值输出显示
1 |
|
while循环
基本语法1
1 | while [ 条件判断式 ] |
注意:while和[有空格,条件判断式和[也有空格
应用实例testWhile.sh
案例1:从命令行输入一个数n,统计从1+…+n的值是多少?
1 |
|
read读取控制台输入
基本语法
read(选项)(参数)
选项:
-p:指定读取值的提示符
-t:指定读取值时等待的时间(秒),如果没有在指定的时间内输入,就不再等待了。
参数:
变量:指定读取值的变量名
应用实例testRead.sh
案例1:读取控制台输入一个NUM1值
案例2:读取控制台输入一个NUM2值,在10秒内输入
1 |
|
函数
shell编程和其他编程语言一样,有系统函数,也可以自定义函数。
系统函数
basename基本语法
功能:返回完整路径最后/的部分,常用于获取文件名
basename [pathname] [suffix]
basename [string] [suffix] (功能描述:basename命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。
选项:
suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
应用实例
案例1:请返回/home/aaa/test.txt的”test.txt“部分
1 | [root@lmh100 shcode]# basename /home/aaa/test.txt |
dirname基本语法
功能:返回完整路径最后/的前面的部分,常用于返回路径部分
dirname 文件绝对路径(功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)
应用实例
案例1:请返回/home/aaa/test.txt的/home/aaa
1 | [root@lmh100 shcode]# dirname /home/aaa/test.txt |
自定义函数
基本语法
1 | # 函数定义 |
应用实例
案例1:计算输入两个参数的和(动态获取),getSum
1 |
|
Shell编程综合案例
需求分析
1.每天凌晨2:30备份数据库mzlmh到/data/backup/db
2.备份开始和备份结束能够给出相应的提示信息
3.备份后的文件要求以备份时间为文件名,并打包成.tar.gz的形式,比如:2021-03-12_230201.tar.gz
4.在备份的同时,检查是否有10天前备份的数据库文件,如果有就将其删除。

1 | cd /user/sbin |
日志管理
1.日志文件是重要的系统信息文件,其中记录了许多重要的系统事件,包括用户的登录信息、系统的启动信息、系统的安全信息、邮件的相关信息、各种服务相关信息等。
2.日志对于安全来说也很重要,它记录了系统每天发生的各种事情,通过日志来检查错误发生的原因,或者受到攻击时攻击者留下的痕迹。
3.可以这样理解,日志是用来记录重大事件的工具。
系统常用的日志
/var/log/目录就是系统日志文件的保存位置

(下表标红为必须要知道的)

注意:这里lastlog拼错了
日志管理服务rsyslogd
CentOS7.6日志服务是rsyslogd,CentOS6.x日志服务是syslogd。rsyslogd功能更强大。
rsyslogd的使用、日志文件的格式,和syslogd服务兼容的。
原理示意图(日志管理服务和日志的关系):

查看Linux中的rsyslogd服务是否启动
1 | ps aux | grep “rsyslog” | grep -v “grep” |
查询rsyslogd服务的自启动状态
1 | systemctl list-unit-files | grep "rsyslog" |
配置文件:/etc/rsyslog.conf [重点]
编辑文件时的格式为: *.* 存放日志文件
其中第一个*代表日志类型,第二个*代表日志级别
1.日志类型分为:
1 | auth ## pam产生的日志 |
2.日志级别分为:
1 | debug ## 有调用信息的,日志通信最多 |
注意:从上到下,级别从低到高,记录信息越来越少
由日志服务rsyslogd记录的日志文件,日志文件的格式包含以下4列:
1.事件产生的时间
2.产生事件的服务器的主机名
3.产生事件的服务名或程序名
4.事件的具体信息
日志如何查看实例
查看一下/var/log/secure日志,这个日志中记录的是用户验证和授权方面的信息,来分析如何查看

日志管理服务应用实例
在/etc/rsyslog.conf中添加一个日志文件/var/log/mzl.log,当有事件发送时(比如sshd服务相关事件),该文件会接收到信息并保存,演示重启,登录的情况,看看是否有日志保存
日志轮替
日志轮替就是把旧的日志文件移动并改名,同时建立新的空日志文件,当旧日志文件超出保存的范围之后,就会进行删除
日志轮替文件命名
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“日志,用来保存新的日志,以此类推。
注意:
1./etc/logrotate.conf里既可以配置全局的日志轮替策略/规则,也可以单独给某个日志文件指定策略。
2.也可以把某个日志文件的轮替规则,写到/etc/logrotate.d目录,
logrotate配置文件
/etc/logrotate.conf为logrotate的全局配置文件

参数说明
1 | 参数 参数说明 |
把自己的日志加入日志轮替
第一种方法是直接在/etc/logrotate.conf配置文件中写入该日志的轮替策略。
第二种方法是在/etc/logrotate.d/目录中新建立该日志的轮替文件,在该轮替文件中写入正确的轮替策略,因为该目录中的文件都会被”include“到主配置文件中,所以也可以把日志加入轮替。
推荐使用第二种方法,因为系统中需要轮替的日志非常多,如果全都直接写入/etc/logrotate.conf配置文件,那么这个文件的可管理性就会非常差,不利于此文件的维护。
在/etc/logrotate.d/配置轮替文件一览
应用实例
在/etc/logrotate.conf进行配置,或者直接在/etc/logrotate.d/下创建mzllog编写如下内容,具体轮替的效果可以参考/var/log下的boot.log情况
1 | /var/log/mzl.log |
日志轮替机制原理
日志轮替之所以可以在指定的时间备份日志,是依赖于系统定时任务。
在/etc/cron.daily/目录,就会发现这个目录中是由logrotate文件(可执行),logrotate通过这个文件依赖定时任务执行的。

查看内存日志
有一部分日志先写到内存里面,还没有写到文件里。
journalctl 可以查看内存日志,这里我们看看常用的指令
1 | journalctl ## 查看全部 |
注意:journalctl 查看得是内存日志,重启会清空
定制自己的Linux系统
通过裁剪现有Linux系统(CentOS7.6),创建属于自己的min Linux小系统,可以加深我们对linux的理解。
基本原理
启动流程介绍:
制作Linux小系统前,再了解一下Linux的启动流程:
1.首先Linux要通过自检,检查硬件设备有没有故障
2.如果有多块启动盘的话,需要在BIOS中选择启动磁盘
3.启动MBR中的bootloader引导程序
4.加载内核文件
5.执行所有进程的父进程、老祖宗systemd
6.欢迎界面
在Linux的启动流程中,加载内核文件时关键文件:
1)kernel文件:vmlinuz-3.10.0-957.el7.x86_64
2)initrd文件:initramfs-3.10.0-957.el7.x86_64.img
制作min linux思路分析
1.在现有的Linux系统(centos7.6)上加一块硬盘/dev/sdb,在硬盘上分两个分区,一个是/boot,一个是/,并将其格式化。需要明确的是,现在加的这个硬盘在现有的Linux系统中是/dev/sdb,但是,当我们把东西全部设置好时,要把这个硬盘拔除,放在新的系统上,此时,就是/dev/sda。
2.在/dev/sdb硬盘上,将其打造成独立的Linux系统,里面的所有文件是需要拷贝进去的
3.作为能独立运行的Linux系统,内核是一定不能少,要把内核文件和initramfs文件也一起拷到/dev/sdb上
4.以上步骤完成,我们的自制Linux就完成,创建一个新的linux虚拟机,将其硬盘指向我们创建的硬盘,启动即可
操作步骤
1.首先,我们在现有的linux添加一块大小为20G的硬盘(注意添加过程中,一定要将虚拟磁盘存储为单个文件)
注意:由于之前在学习挂载的时候,添加了一块硬盘,所以移除后如果不在配置文件/etc/fstab将永久挂载点删除,则开机会进入紧急模式。解决的办法是:进入紧急模式后,输入root密码,编辑/etc/fstab,将之前的sdb硬盘挂载指示内容删除,再重启。如果开机进入了紧急模式,可能是因为刚刚移除硬盘后
2.接下来进行分区和格式化
1)先用lsblk查看目前有哪些硬盘。
2)对硬盘进行分区
1 | fdisk /dev/sdb |
3)对硬盘进行格式化
1 | mkfs.ext4 /dev/sdb1 |
4)创建目录,并挂载新的磁盘
1 | mkdir -p /mnt/boot /mnt/sysroot # 创建目录 |
5)安装grub2,内核文件拷贝至目标磁盘
1 | grub2-install --root-directory=/mnt /dev/sdb # 安装grub2 |
6)修改grub2/grub.cfg文件中的UUID(指定那些盘是启动盘,哪些盘是根目录盘),标红的部分是需要使用指令来查看的
(用sed -i全部替换更方便)
在UTF-8后面要加一句话selinux=0 init=/bin/bash,代表不要走系统那条线,要走我自己定制的shell
在linux16最后也要加上selinux=0 init=/bin/bash
保存退出
7)创建目标主机根文件系统(将所有重要目录建起来,虽然是空的)(注意/mnt/sysroot和{}之间没有空格)
1 | mkdir -pv /mnt/sysroot/{etc/rc.d,usr,var,proc,sys,dev,lib,lib64,bin,sbin,boot,srv,mnt,media,home,root} |
8)拷贝需要的bash(也可以拷贝你需要的指令)和库文件给新的系统使用
1 | cp /lib64/*.* /mnt/sysroot/lib64/ |
9.原虚拟机先关机,然后新创建一个虚拟机,然后将默认分配的硬盘移除掉,指向我们刚刚创建的磁盘即可。
10)这时,很多指令都不能使用,比如ls,reboot等,可以将需要的指令拷贝到对应的目录即可
11)如果要拷贝指令,重新进入到原来的linux系统拷贝相应的指令即可,如将/bin/ls拷贝到/mnt/sysroot/bin,将/sbin/reboot拷贝到/mnt/sysroot/sbin
1 | mount /dev/sdb2 /mnt/sysroot/ # 重新挂载 |
12)再重启新的min linux系统,就可以使用ls,reboot指令了
额外阅读:Linux内核源码-介绍&内核升级
linux0.01内核源码
基本介绍
Linux的内核源代码可以从网上下载,解压缩后文件文件一般也都位于linux目录下。内核源代码有很多版本,可以从linux0.01内核入手,总共的代码1w行左右,版本5.9.8总共代码超过700w行,非常庞大。
linux0.01内核源码目录&阅读
阅读内核源码技巧
1.linux0.01的阅读需要懂c语言
2.阅读源码前,应知道Linux内核源码的整体分布情况。现代的操作系统一般由进程管理、内存管理、文件系统、驱动程序和网络等组成。Linux内核源码的各个目录大致与此相对应。
3.在阅读方法或顺序上,有纵向与横向之分。所谓纵向就是顺着程序的执行顺序逐步进行(比如从主方法开始阅读);所谓横向,就是按模块进行,它们常结合在一起进行(比如先看内存管理mm模块)。
4.对于Linux启动的代码可顺着Linux的启动顺序一步步来阅读;对于像内存管理部分,可以单独拿出来进行阅读分析。实际上这是一个反复的过程,不可能读一遍就理解
linux内核源码阅读&目录介绍&main.c说明

main.c中

linux内核升级应用实例
将Centos系统从7.6内核升级到7.8版本内核(兼容性问题)
具体步骤
1 | uname -a //查看当前的内核版本 |
注意:装了新的内核后,使用uname -a,仍显示原内核。重启之后,在重启界面可以选择新内核。新内核是兼容原先的系统的。
备份与恢复
实体机无法做快照,如果系统出现异常或者数据损坏,后果严重,要重做系统,还会造成数据丢失。所以我们可以使用备份和恢复技术
linux的备份和恢复很简单,有两种方式:
1.把需要的文件(或者分区)用TAR打包就行,下次需要恢复的时候,再解压开覆盖即可
2.使用dump和restore命令
安装dump和restore
如果linux上没有dump和restore指令,需要先安装
1 | yum -y install dump (可能会同时安装上restore) |
使用dump完成备份
dump支持分卷和增量备份(所谓增量备份是指备份上次备份后 修改/增加过的文件,也称差异备份)。
示意图:
第一次备份层级为0,表示完整备份。后面的层级表示增量备份/差异备份/层级备份。
dump语法说明
dump [-cu] [-123456789] [-f <备份后文件名>] [-T <日期>] [目录或文件系统]
dump []-wW
-c(c是一个数字,可以是0-9中的一个数字):创建新的归档文件,并将由一个或多个文件参数所指定的内容写入归档文件的开头。
-0123456789:备份的层级。0为最完整备份,会备份所有文件。若指定0以上的层级,则备份自上一次备份以来修改或新增的文件,到9后,可以再次轮替。
-f <备份后文件名>:指定备份后文件名
-j:调用bzlib库压缩备份文件,也就是将备份后的文件压缩成bz2格式,让文件更小
-T <日期>:指定开始备份的时间与日期
-u:备份完成后,在/etc/dumpdares中记录备份的文件系统,层级,日期与时间等。(不带u则不知道备份到第几次了)
-t:指定文件名,若该文件已存在备份文件中,则列出名称
-W:显示需要备份的文件及其最后一次备份的层级,时间,日期。
-w:与-W类似,但仅显示需要备份的文件。
应用案例1
将/boot分区所有内容备份到/opt/boot.bak.bz2文件中,备份层级为’0’
1 | dump -0uj -f /opt/boot.bak0.bz2 /boot |
dump应用案例2
在/boot目录下增加新文件,备份层级为”1”(只备份上次使用层级”0“备份后发生过改变的数据),注意比较看看这次生成的boot1.bak有多大
1 | dump -1uj -f /opt/boot.bak1.bz2 /boot |

注意:通过dump命令在配合cronbtab可以实现无人值守备份
dump -W
显示需要备份的文件及其最后一次备份的层级,时间,日期
查看备份时间文件
1 | cat /etc/dumpdates |

dump备份文件或者目录
前面我们在备份分区时,是可以支持增量备份的,如果备份文件或者目录,不再支持增量备份,即只能只用0级别备份
案例:使用dump备份/etc整个目录
dump -0j -f /opt/etc0.bak.bz2 /etc/
1 | # 下面这条语句会报错,提示DUMP:Only level0 dumps are allowed on a subdirectory |
注意:重要的备份文件,比如数据区,建议将文件上传到其他服务器保存,不要将鸡蛋放在同一个篮子。
使用restore完成恢复
restore命令用来恢复已备份的文件,可以从dump生成的备份文件中恢复原文件
restore基本语法
restore [模式选项] [选项]
说明下面四个模式,不能混用,在一次命令中,只能指定一种。
-C:使用对比模式,将备份的文件与已存在的文件相互对比。
-i:使用交互模式,在进行还原操作时,restores指令将依序询问用户
-r:进行还原模式(用的最多的模式)
-t:查看模式,看备份文件有哪些文件
选项
-f <备份设备>:从指定的文件中读取备份数据,进行还原操作
应用案例1
restore命令比较模式,比较备份文件和原文件的区别
测试
1 | mv /boot/hello.java /boot/hello100.java |

mv /boot/hello100.java /boot/hello.java
restore -C -f boot.bak1.bz2

应用案例2
restore命令查看模式,看备份文件中有哪些数据/文件
测试
1 | restore -t -f boot.bak1.bz2 |

应用案例3
restore命令还原模式,注意细节:如果你有增量备份,需要把增量备份文件也进行恢复,有几个增量备份文件,就要恢复几个,按顺序来恢复即可。
测试
1 | mkdir /opt/boottmp |
应用案例4
restore命令恢复备份的文件,或者整个目录的文件
基本语法:restore -r -f 备份好的文件
测试
1 | mkdir etctmp |