Contents
关于Linux的shell脚本,是由函数以及逻辑控制语句将一些命令按照特定的目的组合在一起,性能特定的功能模块集合。这个命令集合可以用于以后对相同场景的重复应用。而可重用,也是实现脚本的一个初衷吧,将重复的工作交给脚本来完成。
下面通过几个例子,慢慢复杂化这种命令集合。
1. 单行命令组合获取特定的信息
这块将会通过3个简单的示例,通过一行命令获取特定的信息。
1.1. 统计/etc/passwd文件中默认shell为/sbin/nologin的用户个数,并显示用户名
先看完整的命令以及结果:
root@ubuntu20u04:~/test# gawk -F':' '$7 ~ /sbin\/nologin/ {sum+=1; print $1 " ==> " $7} END{print "User_Count: " sum}' passwd daemon ==> /usr/sbin/nologin bin ==> /usr/sbin/nologin sys ==> /usr/sbin/nologin games ==> /usr/sbin/nologin man ==> /usr/sbin/nologin lp ==> /usr/sbin/nologin mail ==> /usr/sbin/nologin news ==> /usr/sbin/nologin uucp ==> /usr/sbin/nologin proxy ==> /usr/sbin/nologin www-data ==> /usr/sbin/nologin backup ==> /usr/sbin/nologin list ==> /usr/sbin/nologin irc ==> /usr/sbin/nologin gnats ==> /usr/sbin/nologin nobody ==> /usr/sbin/nologin systemd-network ==> /usr/sbin/nologin systemd-resolve ==> /usr/sbin/nologin systemd-timesync ==> /usr/sbin/nologin messagebus ==> /usr/sbin/nologin syslog ==> /usr/sbin/nologin _apt ==> /usr/sbin/nologin uuidd ==> /usr/sbin/nologin tcpdump ==> /usr/sbin/nologin landscape ==> /usr/sbin/nologin sshd ==> /usr/sbin/nologin systemd-coredump ==> /usr/sbin/nologin slackware ==> /sbin/nologin User_Count: 28 root@ubuntu20u04:~/test#
上述命令中,通过一条
gawk
命令,列出了默认shell为/sbin/nologin的用户并且统计了总共的用户个数。gawk
命令的-F':'
选项等同于默认变量FS=':'
,表示文件的域分隔符,默认为空白符,此处采用:号来分隔/etc/passwd文件中的各个域。另外,通过指定第7域是否能够匹配(~)/sbin/nologin,来决定是否执行后面的对sum的自加操作,如果能够匹配,则将sum加1,每匹配到一行,则执行一次加1操作,并且将该行的用户名以及对应的默认shell打印出来。当所有行都循环迭代完成之后,此时
gawk
的语句体部分就会执行END部分的语句,此时打印sum值,即为搜索过所有行之后,将所有默认shell为/sbin/nologin的行相加在一起的结果。通过gawk
命令的内建
1.2. 列出/etc/passwd文件中UID最大的值,以及对应的用户名、和默认shell
先看具体的代码以及执行结果,具体如下所示:
root@ubuntu20u04:~/test# max_uid=`gawk -F':' 'BEGIN{uid=0} {if($3 > uid) uid=$3} END{print uid}' passwd` root@ubuntu20u04:~/test# gawk -F':' -v maxuid=$max_uid '{if($3 == maxuid) print "maxuid_name: "$1, "\nmaxuid_uid: "$3, "\nmaxuid_shell: "$7}' passwd maxuid_name: nobody maxuid_uid: 65534 maxuid_shell: /usr/sbin/nologin root@ubuntu20u04:~/test#
上述代码中,同样用到了
gawk
这个命令,以及命令替换,命令替换有两种形式:第一种为上述的反引号括起来的部分,即第一行中,等号后面的内容,为命令替换的部分;第二种为$()的这种形式,将上述反引号中的命令内容放置到上述的小口号中即可。上述第一行获得到了/etc/passwd文件中的最大的UID的数值。第二行命令通过gawk的-v选项,将shell变量转换为gawk的变量,在gawk中引用变量内容是无需使用$符号进行引用的,所以在gawk的语句体中使用maxuid这个变量的时候,是无需加$符号进行引用的。
上述第二行代码中,gawk的语句体部分,通过搜索/etc/passwd文件中的所有行的第3域是否为max_uid中记录的最大值,如果是,则打印出用户名、用户ID以及其默认shell。
1.3. 统计当前主机中远程连接IP的连接数,并按从大到小进行排序
先看下面的具体命令以及结果,具体如下所示:
root@ubuntu20u04:~/scripts# ss -nta -4 | tr -s ' ' | cut -d' ' -f 4 | tail -n+2 | cut -d':' -f1 | sort -n | uniq -c | sort -nr -k1 | egrep -v 127\. 2 192.168.122.30 2 0.0.0.0 root@ubuntu20u04:~/test#
上述通过
ss
命令列出所有到本机的连接,通过-4选项表示仅输出IPV4格式的IP地址,通过tr -s ' '
将每行的多个空格压缩为1个,随后通过cut
命令提取出IP地址。要统计各个ip地址对本机的连接次数,就需要用到
uniq -c
这个命令,而这个命令要想达到期望的结果,就需要对结果进行排序之后再应用该命令,所以该命令通常用在sort
命令之后,通过管道,将sort
的排序结果输出给uniq
进行统计。最后的
egrep -v 127\.
表示对搜索pattern进行取反,即不显示被127.匹配到的行。
2. 通过脚本获取特定的信息
2.1. 通过脚本显示当前系统分区中利用率最高的分区
脚本内容如下所示:
#!/bin/bash #*********************************************************** # Name: disk.sh # Vers: v0.1 # Auth: 六弦企鹅 # Modi: 2021-04-04 # Desc: find out the max usage of partion # Usag: bash disk.sh #*********************************************************** echo 'System partition usage: ' df -hT | egrep 'ext|xfs' | sort -nr -k6 | gawk '{print "Used: "$6, "Partition: "$7}' echo -e '\n*******************************************************\n' echo 'Max partition Usage: ' max_usage=`df -hT | egrep 'ext|xfs' | sort -nr -k6 | gawk '{print "Used: "$6, "Partition: "$7}' | head -n1` echo -e "\e[1;42;31m$max_usage\e[0m"
上述脚本中,过滤出文件系统类型为’ext’或者’xfs’的分区,由于其他分区多为tmpfs类型的分区,是内存分区,不占用磁盘空间,所以并不做统计。而要在
df
命令的输出中显示文件系统类型,就需要加上额外的选项-T
才可以。随后通过排序,将结果按照利用率从高到底进行排序,这是通过
sort -nr -k6
这条命令实现的,选项-nr
表示按照数字进行反向排序,即从大到小排序;选项-k6
表示对第6域进行排序。随后将排序结果通过管道输出给
gawk
命令,并打印出使用率以及挂载点。而要打印使用率最高的分区,由于此前是按照使用率从高到低进行排序的,所以此处直接通过
head -n1
命令即可取出使用率最高的分区。另外,在上述输出中,还增加了颜色,颜色控制部分的结构为"\e[1;42;31m…\e[0m",其中1表示加粗,42表示设置背景色,31表示设置字体的前景色。最后的0表示颜色应用的范围终止,该条命令之后的内容不做颜色控制。
上述脚本的执行效果如下:
root@ubuntu20u04:~/scripts# bash disk.sh System partition usage: Used: 46% Partition: /boot Used: 27% Partition: / ******************************************************* Max partition Usage: Used: 46% Partition: /boot root@ubuntu20u04:~/scripts#
图示结果如下:
2.2. 通过脚本systeminfo.sh显示主机的系统信息
脚本的具体内容以及执行效果具体如下所示:
#!/bin/bash #************************************************************ # Name: systeminfo.sh # Vers: v0.1 # Auth: 六弦企鹅 # Modi: 2021-04-04 # Desc: output basic informations of the system # Usag: bash systeminfo.sh #*********************************************************** # 1. output hostname host_name=`hostname` # 2. ipv4 address ipv4_address=`ip addr show enp1s0 | gawk '/inet /{print $2}' | cut -d'/' -f1` # 3. os version # both RHEL/CentOS and Ubuntu all have this file os_vers=`egrep -i 'pretty_name' /usr/lib/os-release | cut -d'"' -f2` # 4. CPU model cpu_model=`lscpu | egrep -i 'model name' | cut -d':' -f2 | tr -s ' ' | egrep -o '[[:alpha:]].*'` # 5. memory size mem_size=`lsmem | egrep -i 'total online memory' | egrep -o '[[:digit:]]{1,}[G|g|T|t|M|m]{1}'` # 6. disk info disk_info=`df -hT | egrep 'ext|xfs' | gawk '{print "device: "$1, "\ntotal_size: "$3, "\nused_percent: "$6, "\nmount_point: "$7; print "\n"}'` # exit the script function exit_query(){ echo -e 'Exiting the Query...' exit 0 } PS3='Enter a number to view the information about the system(1-7): ' select info in host_name ipv4_address os_vers cpu_model mem_size disk_info exit_query do case $REPLY in 1) echo -e "\e[1;37mHostName: \e[0m \e[1;33m$host_name\e[0m" ;; 2) echo -e "\e[1;37mIPADDRESS: \e[0m \e[1;33m$ipv4_address\e[0m" ;; 3) echo -e "\e[1;37mOS_VERSION: \e[0m \e[1;33m$os_vers\e[0m" ;; 4) echo -e "\e[1;37mCPU_MODEL: \e[0m \e[1;33m$cpu_model\e[0m" ;; 5) echo -e "\e[1;37mMEMORY_SIZE: \e[0m \e[1;33m$mem_size\e[0m" ;; 6) echo -e "\e[1;37mDISK_INFO: \e[0m \e[1;33m$disk_info\e[0m" ;; 7) exit_query ;; *) echo -e "\e[1;31mInvalid value, PLEASE ReENTER!!!\e[0m" ;; esac done
上述脚本的执行效果如下所示:
root@ubuntu20u04:~/scripts# bash systeminfo.sh 1) host_name 2) ipv4_address 3) os_vers 4) cpu_model 5) mem_size 6) disk_info 7) exit_query Enter a number to view the information about the system(1-7): 1 HostName: ubuntu20u04 Enter a number to view the information about the system(1-7): 2 IPADDRESS: 192.168.122.30 Enter a number to view the information about the system(1-7): 3 OS_VERSION: Ubuntu 20.04.2 LTS Enter a number to view the information about the system(1-7): 4 CPU_MODEL: AMD EPYC Processor (with IBPB) Enter a number to view the information about the system(1-7): 5 MEMORY_SIZE: 2G Enter a number to view the information about the system(1-7): 6 DISK_INFO: device: /dev/mapper/vg0-lv--0--root total_size: 46G used_percent: 27% mount_point: / device: /dev/vda2 total_size: 469M used_percent: 46% mount_point: /boot Enter a number to view the information about the system(1-7): 7 Exiting the Query... root@ubuntu20u04:~/scripts#
图示结果如下图所示:
上述脚本中,用到了函数function,以及select语句结构和case条件选择语句结构。
对于function的定义,主要有三种形式:
- func_name(args) {commands}
- function func_name {commands}
- function func_name(args) {commands}
select语句结构的一些说明
select语句结构的输出提示部分会占用系统的PS3提示符,所以此处将提示信息赋值给PS3这个系统变量,另外,select语句体中的输入值会存储在默认的环境变量REPLY中,所以后面case语句体中会对该变量进行值判断。由于select也是一种循环结构,所以在语句体部分也是以do开头,以done结尾。case语句结构的一些说明
case语句作为条件选择语句,同if条件判断语句的语法结构类似,也是以逆序的case作为语句体的结尾。其中每个选择子句中的结尾都要以双分号结尾。