Linux教程

Linux随笔11-shell小脚本(排序、索引数组在while循环中的应用)

本文主要是介绍Linux随笔11-shell小脚本(排序、索引数组在while循环中的应用),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Contents

  • 1. 显示统计占用系统内存最多的进程,并排序
  • 2. 使用for和while分别实现192.168.122.0/24网段内,地址是否能够ping通
    • 2.1. for循环的脚本内容
    • 2.2. while循环的脚本内容
  • 3. 通过计划任务执行脚本进行配置文件备份
  • 4. 通过计划任务执行脚本进行磁盘空间检查
  • 5. 彩蛋

一些简单功能的shell脚本,Linux系统运维自然离不开shell脚本的编写,shell脚本虽然名曰脚本,但是麻雀虽小,五脏俱全。循环迭代,条件判断,数组,变量,函数等功能一应俱全。

1. 显示统计占用系统内存最多的进程,并排序

要完成这个需求,需要用到ps命令列出系统的进程信息,并在其中挑选内存占用相关的列对其排序。

具体如下所示:

[root@LiuXianQiE ~]# gawk 'BEGIN{printf "%-4s %-12s %-12s %-50s\n", "M%", "VSZ", "RSS", "PROCESS"}' && ps aux | gawk '{if(NR>1) {printf "%-4s %-12s %-12s %-50s\n", $4, $5, $6, $11}}' | sort -nr -k1 | head -n20
M%   VSZ          RSS          PROCESS                                             
3.4  7448156      2239152      /usr/libexec/qemu-kvm                               
1.5  7086800      1002952      /usr/libexec/qemu-kvm                               
1.1  3784768      738136       /usr/lib64/firefox/firefox                          
1.0  3516932      695080       /usr/lib64/firefox/firefox                          
0.9  1246220      631156       /usr/libexec/packagekitd                            
0.3  915212       227488       /opt/google/chrome/chrome                           
0.3  3832492      249556       /usr/bin/gnome-shell                                
0.3  2867744      197704       /usr/lib64/firefox/firefox                          
0.3  2818888      205508       /usr/lib64/firefox/firefox                        
0.3  2771884      244292       /usr/lib64/firefox/firefox                          
0.3  2741108      205004       /usr/lib64/firefox/firefox                          
0.3  1825340      224156       qv2ray                                              
0.2  4864792      136540       /opt/google/chrome/chrome                         
0.2  3473784      159760       /usr/bin/gnome-shell                                
0.2  1769708      188816       /usr/libexec/platform-python                        
0.2  1197388      144872       /usr/bin/gnome-software                           
0.1  779540       127436       /opt/google/chrome/chrome                           
0.1  6991284      107840       /usr/bin/v2ray                                      
0.1  545832       85856        /opt/google/chrome/chrome                         
0.1  4842656      121068       /opt/google/chrome/chrome                           
[root@LiuXianQiE ~]# 

在上述输出中,将系统中的进程按照内存的使用率所占的百分比从高到低进行排序,同时输出了进程的VSZ以及RSS信息。VSZ表示进程所占用的虚拟内存大小(virtual memory size),以KiB为单位(1024字节);RSS表示进程的常驻内存大小(resident set size),即进程所占用的非交换物理内存大小以KiB为单位(1024字节)。
除此之外,上述命令中用到了gawk,其中的循环体部分应用到了if条件判断,gawk中的条件判断不同于shell脚本中的if条件判断,其形式更类似与C语言的风格。NRgawk中提供的变量,表示当前循环处理的行数,此处使用NR>1表示忽略掉标题行,从真正的包含进程信息的行开始进行信息提取以及排序操作。
同时还用到了gawkprintf格式化打印输出操作,并且在gawk中通过这个格式化打印操作进行显示格式控制,并给排序后的结果添加标题。在包含printf语句的gawk中,其语句体部分需要用单引号,然后在语句体内部对于格式化表达式以及待格式化的内容均使用双引号。其中printf语句与格式化表达式之间用空格分隔;格式化表达式如果是列表,则需要将这个列表用双引号括起来,同时多个格式化表达式之间用空格分隔。后面的待格式化内容部分如果是纯文本,则必须要用双引号括起来,且彼此之间用英文半角逗号分隔;如果是变量,则无需用双引号。否则会导致如下问题:

[root@LiuXianQiE ~]# gawk "BEGIN{printf '%4s %12s %12s %50s\n', 'M%', 'RES', 'VSS', 'PROCESS'}"
gawk: cmd. line:1: BEGIN{printf '%4s %12s %12s %50s\n', 'M%', 'RES', 'VSS', 'PROCESS'}
gawk: cmd. line:1:              ^ invalid char ''' in expression
gawk: cmd. line:1: BEGIN{printf '%4s %12s %12s %50s\n', 'M%', 'RES', 'VSS', 'PROCESS'}
gawk: cmd. line:1:              ^ syntax error
[root@LiuXianQiE ~]#

从上述输出中可以看出,当gawk的主语句体部分使用双引号,语句体中的printf语句中的格式化表达式使用单引号的时候,就会提示上述语法错误。
关于格式化语句printf的使用方法,参见man gawk的帮助手册,在其中输入/printf进行搜索即可。这个语句有两种使用形式,分列如下:

  • printf fmt, expr-list,这个语句将格式化的内容打印到标准输出流中
  • printf fmt, expr-list >file,这个语句将格式化的内容写入到文件中
    printf语句中常用的格式化控制符如下:
  • %c:表示单个字符
  • %d, %i:这两个表示输出内容为十进制整数
  • %e, %E:这两个表示输出内容为浮点数,显示形式为[-]d.dddddde[+-]dd
  • %f, %F:这两个表示输出内容为浮点数,显示形式为[-]ddd.dddddd
  • %g, %G:这两个表示输出内容为浮点数,使用%e或者%f转换而来,但是更短,且会压缩掉无意义的数字0
  • %o:表示输出为无符号的八进制数
  • %u:表示输出为无符号的十进制整数
  • %s:表示输出为字符串,不同于%c输出的单个字符
  • %x, %X:表示输出为无符号十六进制数,%x使用abcdef,%X使用ABCDEF
  • %%:输出单一%
    除了上述的格式化控制表达式之外,在%与格式化控制字符之间还可以出现如下内容,对显示内容进行控制:
  • count$:表示在格式化表达式中使用第count个参数,被称为位置标定符,是gawk的扩展,在awk则不存在该内容
  • -:表示左对齐,默认为右对齐
  • space:如果输出的是有符号的十进制数,负数在数字前面加上-号,整数在数字前面加上一个空格
  • +:用在宽度修饰符的前面,相比于space的正数前面加空格,负数前面加-号更进一步;即在正数前面加+号,在负数前面加-号。且其优先级比space
  • #:表示某些控制字符的可选形式,比如对于%o而言,则为其提供前导0,以便表示八进制数;对于%x,%X而言,则是提供前导的0x或者0X表示十六进制数
  • 0:表示对于输出内容填补0而不是空格,这个格式控制只出现在数值类型的格式化打印输出中,且只在格式化指定的数字宽度比实际的输出内容更宽的时候,才会补0
  • ':表示对于十进制数字使用千分符(thousand-separator),千分符会应用到整数位以及小数位
  • width:表示输出内容所占宽度,比实际内容宽的部分默认会填补空格,如果指定了0,则会填补0
  • .prec:打印小数的时候指定的小数部分的保留位数,即精度

除了上述的gawk部分内容之外,还用到了sort -nr -k1这个命令,其中-n表示对数字进行升序排序,-r选项表示反向排序,即降序排列,-k选项表示指定对哪一列进行排序,此处-k1表示对第一列进行排序,而列划分的分割符默认为空格,如果是其他字符,可以通过-t选项指定,注意:列分隔符只能是单字符。

2. 使用for和while分别实现192.168.122.0/24网段内,地址是否能够ping通

通过ping命令检测网段的中主机网络状态,每个主机发送一个icmp协议数据包(ECHO_REQUEST),且最多等待1秒,以此增加判断速度。为此,使用命令形式为ping -c1 -W1,选项-c1表示发送1个(ECHO_REQUEST)请求数据包,选项-W1表示超时等待1秒。

2.1. for循环的脚本内容

for循环的好处是可以对列表内容进行迭代,列表中的内容迭代完成的时候,自动结束循环体的执行。

具体脚本内容如下所示:

#!/bin/bash


#--------------------------------------------------
# FileName    : ping_host_for_loop.sh
# Author      : 六弦企鹅
# Contact     : 123456789
# Version     : v0.1
# Modify      : 2021-05-29
# Usage       : bash ping_host_for_loop.sh
# Description : check host in 192.168.122.0/24 with for loop
#--------------------------------------------------



ip_prefix=192.168.122.
ip_suffix=`seq 1 254`

for n in ${ip_suffix}
do
    ping -c1 -W1 ${ip_prefix}${n} 2>&1 >/dev/null && echo ${ip_prefix}${n} 'successfully!' || echo ${ip_prefix}${n} 'failed...' &
done

上述脚本中,采用seq 1 254生成主机的IP地址后缀部分,之所以忽略掉0和255,是因为前者代表网段,后者代表广播地址。所以主机IP地址的有效值从1到254。
另外,在上述的循环体内部,ping命令的末尾有一个&,表示将该条命令放在后台执行,即该命令的执行不会阻塞下一次循环迭代中该命令的执行。如果不加&,那么只有在该次ping命令执行完成之后才会开启下次迭代执行ping命令。
上述内容输出的时候,除了打印成功失败的状态之外,还会附加上对应的IP地址信息。其执行结果如下所示:

[root@LiuXianQiE ~]# bash ping_host_for_loop.sh
192.168.122.1 successfully!
192.168.122.2 successfully!
192.168.122.30 successfully!
192.168.122.139 successfully!
192.168.122.3 failed...
192.168.122.6 failed...
192.168.122.7 failed...
192.168.122.5 failed...
192.168.122.8 failed...
192.168.122.10 failed...
192.168.122.11 failed...
192.168.122.12 failed...
...

其他输出省略。

上述即为for循环

2.2. while循环的脚本内容

由于while循环并不能像for循环一样自动迭代列表中的内容,在列表中的内容迭代完成的时候自动退出循环体的执行,其需要认为判断,并且改变列表中的内容,以辅助完成循环。因为while循环中只能对条件进行判断,如果循环条件为true,那么就进入循环体执行;否则不进入循环体执行。
所以此处将IP地址放在索引数组中,并在循环体中控制数组长度,每次迭代剔除最左侧的数组元素,即索引为0的元素,并在循环体开始部分测试0号索引的数组元素是否为空,如果为空,则结束循环。在循环体的末尾对数组长度进行检测,如果数组长度为0,则结束循环。

脚本的具体内容如下所示:

#!/bin/bash

#--------------------------------------------------
# FileName    : ping_host_while_loop.sh
# Author      : 六弦企鹅
# Contact     : 123456789
# Version     : v0.1
# Modify      : 2021-05-29
# Usage       : bash ping_host_while_loop.sh
# Description : 利用while循环,并发检查指定IP范围内的主机状态
#--------------------------------------------------



ip_prefix=192.168.122.
ip_suffix_arr=(`seq 1 254`)

while :
do
   if [ ! -z ${ip_suffix_arr[0]} ]; then           # 如果数组的第一个元素为空的时候,说明此时数组中的所有都遍历完成
       host=${ip_prefix}${ip_suffix_arr[0]}
   else
       break
   fi  

   ping -c1 -W1 ${host} 2>&1 >/dev/null && echo ${host} 'successfully!' || echo ${host} 'failed...' &
   if [ ${#ip_suffix_arr[*]} -gt 0 ]; then         # 判断数组长度是否大于0
       ip_suffix_arr=(${ip_suffix_arr[*]:1})       # 在每次迭代中,剔除掉数组中的第一个元素,即${ip_suffix_arr[0]}
   else
       break
   fi
done

上述脚本的执行结果与for循环的执行结果类似,不再列出。
另外,在上述脚本中,用到的一些数组相关的表达式介绍如下:

  • ${ip_suffix_arr[0]}表示取数组的第一个元素,即索引为0的数组元素。另外,在if条件判断表达式中,[ ! -z ${ip_suffix_arr[0]} ]表示当数组的第一个元素不为空,!号表示取反,-z选项表示判断其后面的表达式是否为空,所以中括号中的内容就表示当数组的第一个元素不为空的时候,这个条件判断表达式的值才为true,否则为false,如果为false,则通过break结束while循环。
  • ${#ip_suffix_arr[*]}表示数组的长度,条件判断表达式[ ${#ip_suffix_arr[*]} -gt 0 ]表示数组的长度大于0的时候,该表达式的值才为true,才会继续执行while循环语句体;否则不执行循环语句体。
  • ${ip_suffix_arr[*]:1}表示对数组进行分片,表示取数组的第二个元素,即索引为1到数组末尾的所有数组元素,以此达到缩减数组元素的目的。表达式ip_suffix_arr=(${ip_suffix_arr[*]:1})表示将缩减后的数组内容赋值给原来的数组变量名字,并用缩减后的数组开始下一次迭代,如此,就可以实现在while循环体中控制循环执行次数的效果,因为外层采用的是无限循环,while :while true的效果相同,都表示无限循环,即死循环。所以此时需要在while循环体内部通过条件判断以及break来控制循环迭代的次数。

关于上述的条件判断表达式的具体内容,参见man test帮助手册。此处不再展开。

3. 通过计划任务执行脚本进行配置文件备份

每周的工作日1:30,将/etc备份至/backup目录中,保存的文件名称格式 为“etcbak-yyyy-mm-dd-HH.tar.xz”,其中日期是前一天的时间。
要满足上述要求,就需要些一个备份脚本。其中最后一句话是关键,决定了备份文件名称的动态生成。

其执行结果如下所示:

root@ubuntu20u04:~/scripts# date +%F-%H -d '-1day'
2021-05-28-22

在上述输出中,通过'+%F-%H'实现时间的格式化显示,但是,此时显示的是当前时间,而要求的备份文件名称中记录的是前一天的时间,所以此处需要使用-d '-1day'表示前一天的时间。-d选项的使用说明为 -d, --date=STRING:display time described by STRING, not 'now’
备份脚本的内容如下所示:

#!/bin/bash


#--------------------------------------------------
# FileName    : backup_etc.sh
# Author      : 六弦企鹅
# Contact     : 123456789
# Version     : v0.1
# Modify      : 2021-05-29
# Usage       : bash backup_etc.sh
# Description : 
#--------------------------------------------------


tobe_backup=/etc
dest_dir=/backup

filename=etcbak-`date '+%F-%H' -d '-1day'`.tar.xz

if [ -d ${dest_dir} ]; then
	chmod 750 ${dest_dir}
	tar cJvf ${dest_dir}/${filename} ${tobe_backup} 2>&1 > /dev/null
else
	mkdir ${dest_dir}
	chmod -R 750 ${dest_dir}
	tar cJvf ${dest_dir}/${filename} ${tobe_backup} 2>&1 > /dev/null
fi

上述通过tar命令进行归档压缩,并将归档结果存储在/backup目录中。另外会判断存放备份文件的目录是否存在,如果该目录不存在,则自动创建该目录,并且将权限修改为750,即root用户具有完全权限,root组用户具有读取和执行权限,其他用户不具有任何权限。
脚本创建完成之后,接下来就是创建计划任务,执行crontab -e命令创建计划任务,并启动cron服务。具体如下所示:

root@ubuntu20u04:/backup# crontab -e
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command
 30 1 * * 1-5 /bin/bash /root/scripts/backup_etc.sh

上述最后一行就添加了计划任务,30代表时间点的30分,1代表时间的小时,这两个结合在一起,表示1:30分,后面的两个*表示每天,每月,1-5表示周1到周五,所以上述的含义就是,每周一到每周五这5天的凌晨1:30分执行备份脚本。
备份脚本以及计划任务创建完成之后,接下来看看cron这个服务是否处于运行状态并且开机自动启动。具体如下所示:

root@ubuntu20u04:/backup# systemctl enable --now cron.service
root@ubuntu20u04:/backup# systemctl status cron.service
. cron.service - Regular background program processing daemon
     Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2021-05-23 17:52:28 CST; 6 days ago
       Docs: man:cron(8)
   Main PID: 1107 (cron)
      Tasks: 1 (limit: 2280)
     Memory: 32.0M
     CGroup: /system.slice/cron.service
             └─1107 /usr/sbin/cron -f

May 30 13:05:01 ubuntu20u04.localhost CRON[2014063]: (root) CMD (bash /root/deny_ddos.sh)
May 30 13:05:01 ubuntu20u04.localhost CRON[2014065]: (root) CMD (command -v debian-sa1 > /dev/null && debian-sa1 1 1)
May 30 13:05:01 ubuntu20u04.localhost CRON[2014061]: pam_unix(cron:session): session closed for user root
May 30 13:05:01 ubuntu20u04.localhost CRON[2014062]: pam_unix(cron:session): session closed for user root
May 30 13:15:01 ubuntu20u04.localhost CRON[2020365]: pam_unix(cron:session): session opened for user root by (uid=0)
May 30 13:15:01 ubuntu20u04.localhost CRON[2020366]: (root) CMD (command -v debian-sa1 > /dev/null && debian-sa1 1 1)
May 30 13:15:01 ubuntu20u04.localhost CRON[2020365]: pam_unix(cron:session): session closed for user root
May 30 13:17:01 ubuntu20u04.localhost CRON[2021635]: pam_unix(cron:session): session opened for user root by (uid=0)
May 30 13:17:01 ubuntu20u04.localhost CRON[2021636]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
May 30 13:17:01 ubuntu20u04.localhost CRON[2021635]: pam_unix(cron:session): session closed for user root
root@ubuntu20u04:/backup#

至此,就开启了cron.service这个服务。上述备份脚本的执行效果如下所示:

root@ubuntu20u04:~/scripts# bash backup.sh
tar: Removing leading '/' from member names
root@ubuntu20u04:~/scripts# ls /backup
etcbak-2021-05-28-22.tar.xz
root@ubuntu20u04:~/scripts# ll -h /backup
total 568K
drwxr-xr-x  2 root root   41 May 29 22:49 ./
drwxr-xr-x 22 root root  331 May 29 22:41 ../
-rw-r--r--  1 root root 567K May 29 22:52 etcbak-2021-05-28-22.tar.xz

关于crontab进行计划任务管理,以及计划任务中的时间写法和有效取值范围,介绍如下:
cron任务分为三个部分,一部分是时间,一部分是用户身份,第三部分是要执行的命令或者程序,不过由于在实际操作中,创建计划任务的账户一般就是计划任务的主体,所以用户身份可以省略不写。重点在于时间的编写。其中在/etc/crontab这个配置文件中给出了一些说明,具体如下所示:
在这里插入图片描述其中第17行给出了基本的形式,时间部分如果都是星号,则表示每天的每分钟执行执行一次计划任务。下表给出各个位置的星号的含义,以及取值范围。具体如下

第一个星号第二个星号第三个星号第四个星号第五个星号
代表分钟,取值范围0-59代表小时,取值范围0-23代表月份的天,取值范围1-31代表月份,取值范围1-12代表星期,取值范围0-7,其中0和7均代表周日

除了上述的基本取值之外,时间部分还支持以下特殊符号,具体如下表所示:

特殊符号代表含义
星号*表示任意值,比如上图的第18行表示每一天的每个小时的第17分钟都会执行一次这个命令,即1天会执行24次这个命令
逗号,字段分隔符,用在同一个时间单位中的多个值之间的分隔,比如每天的早7点和晚6点,可以写为0 7,18 * * * command
减号-表示连字符,用于指定连续的时间范围。比如每天的8点到12点之间每个小时的第30分钟执行一个操作,可以写为30 8-12 * * * command
正斜线/n表示每隔n个时间间隔,比如每10分钟运行一次,可以写为*/10 * * * * command,也可以写为0-59/10 * * * *,两者效果相同

除了使用上的crontab -e命令创建计划任务之外,还可以使用crontab -l命令列出计划任务。也可以执行crontab -r命令删除计划任务,但是这个命令是打开一个编辑器,需要在这个文本编辑器中由用户手动进行删除操作。具体打开什么编辑器,取决于环境变量EDITOR的值。

4. 通过计划任务执行脚本进行磁盘空间检查

工作日时间,每10分钟执行一次磁盘空间检查,一旦发现任何分区利用率高 于80%,就发送邮件报警。
为了满足时行数要求,就需要在脚本中每十分钟获取一下磁盘空间使用情况,并判断其使用率是否超过80%。然后在计划任务中执行该脚本。

脚本文件的具体内容如下所示:

#!/bin/bash


#--------------------------------------------------
# FileName    : disk_usage_watcher.sh
# Author      : 六弦企鹅
# Contact     : 123456789
# Version     : v0.1
# Modify      : 2021-05-29
# Usage       : bash disk_usage_watcher.sh
# Description : 检查系统中磁盘的空间使用率,超过80%邮件报警
#--------------------------------------------------


critical_value=40
mount_info_lines=`df -hT | egrep -v 'loop|tmpfs' | gawk '{if(NR>1) print $0}' | sed -re ':label;N;s/\n/@/;b label'`
IFS_OLD=$IFS

IFS='@'
for line in ${mount_info_lines}
do
	partition_usag=`echo "${line}" | gawk '{print $6}' | cut -d'%' -f1`
	partition_name=`echo "${line}" | gawk '{print $7}'`
	if [ ${partition_usag} -gt ${critical_value} ]; then
		mail root -s "ATTENTION PLEASE: the usage of ${partition_name} is over critical value" << EOF
		Please check the usage of this partition...
		The name is ${partition_name}, the usage is ${partition_usag}
EOF
	fi
done

在上述脚本中,除了mount_info_lines这一行中使用了sed命令将换行符替换为@符号之后,其他没有特别之处。之所以做如此替换,是因为for循环默认的域输入分割符是空白符、制表符、换行符,而此处要以行为单位进行处理,所以需要用一个特殊的分割符来分隔各个行,以免与for循环的域输入分割符相混淆。指定了@符号位域分隔符之后,就可以使用空白符作为分割符处理每一行中的各个字段了。
在上述的sed -re ':label; N; s/\n/@/; b label'这个语句中,实际上执行了4个操作,即:

  • :label;标签定义部分 - 表示在当前模式空间所在行处设定标签
  • N;读取下一行到模式匹配空间 - 表示将下一行读入到当前模式空间
  • s/\n/@/;命令替换 - 表示将读入到模式匹配空间中的两行之间的换行符替换为@符号
  • b label定位到替换操作完成之后的当前行的位置,并准备执行下一轮循环。除了使用b label之外,还可以使用t labelT label,这三者之间是有区别的。b label表示无条件的跳转到标签定位的地方,此时可以省略开头的标签定义;t label表示当前一步的替换操作成功执行之后,才会跳转到标签定位的地方,直到文本被处理完成或者有其他情况出现;而T label则与t label的含义相反,其是当上一条的替换操作不成功的时候,才会定位到标签定义的地方,直到最后一行被处理完成或者有其他分支出现,此时也可以省略标签定义语句。

另外,在上述脚本中,还是用了默认的IFS变量,将其赋值为@来更改其对行结束符的判断,从而影响其将哪些内容视为1行。IFS对于for循环是有影响的,这也是做如此改变的原因。
上述脚本编写完成之后,接下来就是创建计划任务了。为了测试效果,将阈值从80修改为40,具体如下所示:

root@ubuntu20u04:~/scripts# crontab -e
*/10 * * * * /bin/bash /root/scripts/disk_usage_watcher.sh

上述就完成了计划任务的创建操作。为了使其生效,重启cron.service服务,具体如下所示:

root@ubuntu20u04:~/scripts# systemctl reload cron.service
Failed to reload cron.service: Job type reload is not applicable for unit > cron.service.
root@ubuntu20u04:~/scripts# systemctl restart cron.service
root@ubuntu20u04:~/scripts#

至此,计划任务操作就完成了。
测试脚本的执行,具体如下所示:

root@ubuntu20u04:~/scripts# bash disk_usage_watcher.sh
root@ubuntu20u04:~/scripts# mail
"/var/mail/root": 1 message 1 new
>N   1 root               Sat May 29 23:25  14/622   ATTENTION PLEASE: the usage of /boot is over critical value
? 1
Return-Path: <root@ubuntu20u04.localhost>
X-Original-To: root@ubuntu20u04.localhost
Delivered-To: root@ubuntu20u04.localhost
Received: by ubuntu20u04.localhost (Postfix, from userid 0)
        id F19DC4134EB4; Sat, 29 May 2021 23:25:34 +0800 (CST)
Subject: ATTENTION PLEASE: the usage of /boot is over critical value
To: <root@ubuntu20u04.localhost>
X-Mailer: mail (GNU Mailutils 3.7)
Message-Id: <20210529152534.F19DC4134EB4@ubuntu20u04.localhost>
Date: Sat, 29 May 2021 23:25:34 +0800 (CST)
From: root <root@ubuntu20u04.localhost>

        Please check the usage of this partition...
        The name is /boot, the usage is 46
? quit
Saved 1 message in /root/mbox
Held 0 messages in /var/mail/root
root@ubuntu20u04:~/scripts#

从上述输出中可以看出,当使用率超过40的时候,就会自动给root用户发送邮件,提示哪个分区超过了使用率,当前使用率是多少等信息。

5. 彩蛋

在bash中利用bc命令计算圆周率pi

[root@LiuXianQiE ~]# echo 'scale=12; 4*a(1)' | bc -lq
3.141592653588
[root@LiuXianQiE ~]# echo 'scale=100; 4*a(1)' | bc -lq
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170676
[root@LiuXianQiE ~]# echo 'scale=100; 4*a(1)' | bc -l
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170676
[root@LiuXianQiE ~]#

其中,-l选项表示调用mathlib数学库,如果不指定-l选项,则前面的4*a(1)将会报错。-q表示静默模式,指定不指定该选项对于输出没有影响。scale=12表示小数点保留的位数为12位,用scale表示保留的小数点后的位数。

以上,是本篇博客的全部内容。

这篇关于Linux随笔11-shell小脚本(排序、索引数组在while循环中的应用)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!