实验指导 10 - Shell 编程
学习目标
- 掌握脚本的编辑、运行和调试方法
- 掌握 bash 变量的定义、引用、替换扩展
- 掌握 bash 的各种流程控制语句
- 掌握 bash 函数的定义和调用方法
- 掌握命令行参数的使用方法
- 掌握避免错误的处理方法使得脚本更健壮
任务1:编写一个最小化安装 CentOS7 后的配置脚本
要求:
- 配置 YUM 并更新系统
- 安装 EPEL 仓库
- 导入已安装所有仓库的 GPG 签名文件
/etc/pki/rpm-gpg/RPM-GPG-KEY-*
- 配置所有仓库的国内镜像URL
- 更新系统
- 安装常用的必要的软件
- bash-completion vim-enhanced
- net-tools psmisc yum-cron yum-utils yum-security
- wget curl elinks w3m lftp mailx mutt rsync ntp git bind-utils
- sysstat htop dstat nload nethogs iftop
- rkhunter aide denyhost fail2ban lynis
- 系统基本配置
- 设置语言、时区
- 设置主机名
- 创建一个普通用户并为其设置口令
- 禁用 chrony 和 ntp 服务
- 使用 ntpdate 配置每日时间同步
- 限制每个用户能打开的最大文件数
- 限制仅 wheel 组的人才能使用 sudo 和 su 命令
- 关闭 SELINUX
- 确保网络参数配置正确后关闭 NetworkManager 服务
- 安全配置
- SSH
- 允许使用口令登录但 root 用户只能使用密钥登录
- 预先写入 root 远程 ssh 登录的公钥并为 .ssh 目录及其文件设置安全权限
- 关闭 DNS 反向解析检查
- ssh 回话闲置 5 分钟后自动注销登录
- 安装配置 fail2ban
- 口令
- 口令必须大于12个字符
- 必须至少包含四类字符中的一个
- 网络
- 开启防火墙 22,80,443 端口
- SSH
- 扩展:使
postinstall.sh
脚本同时适用于 CentOS 6/7- Vagrant 自动部署 -- https://www.vagrantup.com/docs/provisioning/shell.html
任务2:根据 shell 类型统计用户数
要求:
- shell 类型通过命令行参数
-s <SHELL>
的形式指定- 显示 shell 类型为 SHELL 的用户数并列出所有用户名
- SHELL 必须是
/etc/shells
文件中存在的类型,否则不执行脚本且退出状态码为1
- 当没有给出命令行参数或命令行参数为
-h | --help
时,显示帮助信息并退出 - 当命令行参数为其他值时,显示提示信息且退出状态码为2
若脚本名为 usersbysh,执行效果如下:
$ usersbysh -s bash
bash - 3 users , they are: root,student,tony
$ echo $?
0
$ usersbysh -s zash
Invalid shell.
$ echo $?
1
$ usersbysh
Usage: usersbysh -s <SHELL>|-h|--help
根据 shell 类型统计用户数并显示用户列表
$ echo $?
0
$ usersbysh --help
Usage: usersbysh -s <SHELL>|-h|--help
根据 shell 类型统计用户数并显示用户列表
$ echo $?
0
$ usersbysh -a
usersbysh:无效选项 -- a
Try 'usersbysh --help|-h' for more information.
$ echo $?
2
任务3:根据用户选择显示不同类型的系统信息
要求:
- 向用户展示功能菜单,具有如下功能:
- 显示所有登录用户
- 显示系统平均负载
- 显示物理内存的使用
- 显示交换空间的使用
- 显示磁盘空间的使用
- quit或q
- 读取用户从键盘上的选择
- 根据不同的选择执行相应的命令
- 选择 quit 或 q 时退出脚本
- 输入错误的选择时退出脚本,且退出状态吗返回1
任务4:任务3扩展
要求:
- 当用户选择显示相应信息后不退出,而让用户继续选择,继续显示相应内容,用户选择 quit 菜单项才退出。
- 使用
while
语句 和select
语句分别完成。
任务5:检测与服务器处于同一子网的每台主机的连通性
要求:
- 通过
ip|ifconfig
命令获取本机 IP 地址- 使用变量替换扩展删除最后一位十进制数
- 通过 ping 命令测试当前主机与 1..254 所有主机的连通性
- 若能 ping 通就显示 "
<IP>
is up.",其中的IP要换为真正的IP地址,且以绿色显示 - 若不能 ping 通就显示"
<IP>
is down.",其中的IP要换为真正的IP地址,且以红色显示
- 若能 ping 通就显示 "
- 请分别使用
while
,until
和for
(两种形式)循环实现
提示 为避免突发性的线路故障发生,在使用 ping 时,每次等待 ping 的响应时间可以设置稍长一些(如:
-W 2
)
任务6:任务5 的函数实现方式
要求:
- 使用函数实现获取本机 IP 地址
- 使用函数实现一台主机的连通性判定
- 在主程序中调用函数判定指定范围内的所有主机的在线情况
扩展 根据子网掩码的值确定要 ping 的主机的 IP 地址范围
任务7:找出使用率大于 90% 的所有分区
要求:
- 使用 read 配合 while 语句实现
- 将 df 命令的输出结果通过管道传递给 while
- 不要对虚拟文件系统进行操作
- 将结果通过邮件发送给 root
- 只有当有使用率大于 90% 的分区时才发送邮件
- 邮件主题为:Warn: Disk Usage on <主机的FQDN>
- 邮件体包含:找出的分区设备名(挂装点)和使用率
- 思考1:循环控制语句
- 若 df 的输出结果以使用率降序排序后再通过管道传递给 while 时,在循环体内可以使用哪个循环控制语句配合条件判断来优化?
- 若 df 的输出结果以使用率升序排序后再通过管道传递给 while 时,在循环体内可以使用哪个循环控制语句配合条件判断来优化?
- 思考2:下面的命令行能完全实现要求的功能吗?为什么?
df -PT |egrep -v '^Filesystem|tmpfs'|sort -nr -k6 | awk '{print $6 , $7}'|mail -s "Warn: Disk Usage on $(hostname -f)" root
df -PT |egrep -v '^Filesystem|tmpfs' | sed 's/%//' |awk '$6>90 {printf "%d%% used on %s (%s)\n", $6, $7, $1}'|mail -s "Warn: Disk Usage on $(hostname -f)" root
任务8:找出使用率大于 N% 的所有分区
任务7 扩展
要求:分别实现如下两种情况
- N 通过命令行参数传递给脚本
- 若 N 不是值为 0~99 的数字,给出出错提示并退出脚本且退出状态码为1
- N 通过 read 从键盘读取
- 使用循环由键盘读取 N,直至读取的值为 0~99 的数字为止
任务9:打印 1~N 之间的所有 奇数|偶数|素数
要求:
- 编写一个函数用于判断一个字符串是否为纯数字的值
- 编写三个函数分别用于打印 1~N 之间的所有 奇数|偶数|素数
- 编写一个函数显示脚本的格式和功能
- 脚本的命令行参数
- 第一个参数必须为一个数字,否则显示使用帮助信息,并设置退出状态码为1
- -o|--odd :打印奇数
- -e|--even:打印偶数
- -p|--prime:打印素数
- -a|--all:打印奇数、偶数和素数
- -h|--help:显示使用帮助信息
- 对于其他的参数应该报错,并设置退出状态码为2
- 可以同时指定多个参数,例如 -o -p 表示既打印奇数又打印素数
提示 命令行参数处理:
getopts
和getopt