Shell 脚本系列
说明:内容来源于网络,并且通过AI工具重新整理归纳。
本文整理了十个实用的 Shell 脚本案例,涵盖日期处理、磁盘监控、日志分析、密码生成、服务监控、YUM 仓库搭建、用户管理、批量建用户、Nginx 服务脚本等高频运维场景。每个案例均包含完整脚本代码与详细解析,可直接复制使用或按需修改。
目录
- 案例一:指定日期的加减计算
- 案例二:获取当前日期和时间及磁盘使用情况
- 案例三:统计 IP 访问情况并分析访问日志
- 案例四:生成随机密码
- 案例五:定时监控 HTTP 服务运行状态
- 案例六:监控 httpd 服务 80 端口状态
- 案例七:开机自动挂载本地 YUM 仓库
- 案例八:Shell 自动化管理账号脚本
- 案例九:自动创建多个新用户并设置密码
- 案例十:编写 Nginx 服务启动程序
案例一:指定日期的加减计算
利用 date -d 参数可以灵活地对日期进行加减操作,是 Shell 脚本中处理日期最常用的方法。
1. 日期减去一天
# 只减去一天,直接写即可
date -d "yesterday 20150401" +%Y%m%d
# 减去指定天数(负数往前数)
date -d "10 day ago 2015-04-01" +%Y-%m-%d
2. 在指定日期上加减小时
# 加上 3 小时 → 输出 2015041615
date -d "20150416 12 3 hour" +"%Y%m%d%H"
# 减去 1 小时 → 输出 2015041611
date -d "20150416 12 -1 hour" +"%Y%m%d%H"
3. 在指定日期上加上分钟
# 加上 10 分钟 → 输出 201504161230
date -d "20150416 12:20 10 minute" +"%Y%m%d%H%M"
4. 常用日期快捷写法
# 本月 / 下月
this_ym=`date +%Y%m`
next_ym=`date -d '1month' +%Y%m`
# 昨天 / 明天
date -d yesterday
date -d tomorrow
date +%Y%m%d -d "+1 day"
date +%Y%m%d --date "+1 day"
# 指定月份
date -d 1May
# 当前时间
date -d now
5. 更多日期偏移用法一览
date +%Y%m%d --date="+1 day" # 后一天
date +%Y%m%d --date="-1 day" # 前一天
date +%Y%m%d --date="-1 month" # 上一月
date +%Y%m%d --date="+1 month" # 下一月
date +%Y%m%d --date="-1 year" # 前一年
date +%Y%m%d --date="+1 year" # 下一年
提示:
date -d功能非常强大,建议熟记,可大幅简化脚本中的日期处理逻辑。
案例二:获取当前日期和时间及磁盘使用情况
习题分析
本题有两个核心知识点:
- 如何自动表示当天的日期
- 如何获取磁盘使用情况
打印日期用 date 命令:
# 默认格式
date
# 输出:2017年 12月 20日 星期三 16:26:55 CST
# 指定格式(两种写法等价)
date +%Y-%m-%d
# 输出:2017-12-20
date +%F
# 输出:2017-12-20
磁盘使用情况用 df -h 实现:
# df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/vda1 99G 1.8G 92G 2% /
devtmpfs 911M 0 911M 0% /dev
tmpfs 920M 0 920M 0% /dev/shm
tmpfs 920M 336K 920M 1% /run
tmpfs 920M 0 920M 0% /sys/fs/cgroup
tmpfs 184M 0 184M 0% /run/user/0
习题答案
#! /bin/bash
d=`date +%F`
logfile=$d.log
df -h > $logfile
答案解析
- 把当天日期赋值给变量
d,从而定义每日的日志文件名 >是输出重定向符号,可把左边命令的结果写入到右边的文件中
扩展知识点
1. 反引号获取命令结果
n=`wc -l /etc/passwd | awk '{print $1}'`
echo $n
# 输出:23
2. date 命令更多用法
date +%H # 小时 → 16
date +%M # 分钟 → 38
date +%S # 秒 → 55
date +%T # 时间 → 16:39:31
date +%w # 星期 → 3
date -d "-1 day" +%F # 一天以前 → 2017-12-19
3. 正确/错误重定向
# > 正确重定向,把正确输出写入文件
# 2> 错误重定向,把错误信息写入文件
ls /etc/passwd /etc/nofile > /tmp/log 2>/tmp/error
cat /tmp/log # 输出:/etc/passwd
cat /tmp/error # 输出:ls: 无法访问/etc/nofile: 没有那个文件或目录
案例三:统计 IP 访问情况并分析访问日志
题目要求
有日志文件 1.log,部分内容如下:
112.111.12.248 - [25/Sep/2013:16:08:31 +0800] "GET /seccode.php?update=0.5593110133088248" 200 "http://formula-x.haotui.com/registerbbs.php" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)"
61.147.76.51 - [25/Sep/2013:16:08:31 +0800] "GET /attachment.php?aid=4554&k=9ce51e2c376bc861603c7689d97c04a1" 301 "http://xyzdiy.5d6d.com/thread-1435-1-23.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322;)"
需求:统计出每个 IP 的访问量有多少。
习题分析
IP 地址在日志的第一段,使用 awk 提取第一段后,再排序并用 uniq -c 统计即可。
习题答案
awk '{print $1}' 1.log | sort -n | uniq -c | sort -n
答案解析
| 命令 | 作用 |
|---|---|
awk '{print $1}' |
提取每段的第一列(即 IP 地址) |
sort -n |
按数字排序(为 uniq 去重做准备) |
uniq -c |
统计每个 IP 出现的次数 |
sort -n |
按访问量从小到大排序 |
注意:
uniq去重的前提是先排序。若想按访问量从大到小排,加-r选项:sort -nr。
案例四:生成随机密码
方法一:urandom 版本
利用 Linux 内置随机设备文件 /dev/urandom 生成密码,再通过 tr 过滤掉不需要的特殊字符。
#!/bin/bash
# Author: 丁丁历险(Jacob)
# /dev/urandom 是 Linux 内置的随机设备文件
# tr -dc '_A-Za-z0-9' 仅保留大小写字母、数字、下划线
tr -dc '_A-Za-z0-9' < /dev/urandom | head -c 10
执行后输出 10 位随机密码,如
aB3kL9mX2p。
方法二:字符串截取版本
自定义密码字符库,用 $RANDOM 取模实现随机选取。
#!/bin/bash
# Author: 丁丁历险(Jacob)
# 密码库:数字 + 大小写字母
key="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
num=${#key} # 统计密码库长度
pass='' # 初始密码为空
# 循环 8 次,生成 8 位随机密码
for i in {1..8}
do
index=$[RANDOM%num]
pass=$pass${key:$index:1}
done
echo $pass
方法三:UUID 版本(16 进制密码)
#!/bin/bash
uuidgen
方法四:进程 ID 版本(纯数字密码)
#!/bin/bash
echo $$
小结:四种方法各有适用场景——urandom 最简单、字符串截取最可控、UUID 最标准、PID 最轻量。
案例五:定时监控 HTTP 服务运行状态
注意:监控方法可以为端口检测、进程检测、URL 模拟访问,或三种方法综合。
版本一:基于进程判断
#!/bin/sh
. /etc/init.d/functions
HTTPPRONUM=`ps -ef | grep http | grep -v grep | wc -l`
if [[ $HTTPPRONUM -lt 1 ]]; then
action "httpd is not running" /bin/false
action "httpd is not running" /bin/false >/tmp/httpd.log
httpdctl restart >/dev/null 2>&1
action "httpd is restart" /bin/true
mail -s "`uname -n`'s httpd restarted at `(date)`" 31333741@qq.com
exit 1
else
action "httpd is running" /bin/true
exit 0
fi
测试效果:
[root@localhost scripts]# apachemon
httpd is running [确定]
[root@localhost scripts]# pkill httpd
[root@localhost scripts]# apachemon
httpd is not running [失败]
httpd is restart [确定]
版本二:基于 URL 判断(改进版)
用 wget --spider 模拟访问,更能反映服务的真实可用性。
#!/bin/sh
# created by oldboy 20110523
. /etc/init.d/functions
wget --quiet --spider http://10.0.0.161/index.htm
if [ $? -ne 0 ]; then
action "httpd is not running" /bin/false >/tmp/httpd.log
httpdctl restart >/dev/null 2>&1
action "httpd is restart" /bin/true >>/tmp/httpd.log
mail -s "`uname -n`'s httpd restarted at `(date)`" 31333741@qq.com
exit 1
fi
版本三:多条件综合判断
同时检测 端口 + 进程 + URL,任一条件不满足即判定为异常。
#!/bin/sh
. /etc/init.d/functions
HTTPPORTNUM=`netstat -lnt | grep 80 | grep -v grep | wc -l`
HTTPPRONUM=`ps -ef | grep http | grep -v grep | wc -l`
wget --quiet --spider http://10.0.0.161/index.htm
RETVAL=$?
if [ $RETVAL -ne 0 ] || [ $HTTPPORTNUM -ne 1 ] || [ $HTTPPRONUM -lt 1 ]; then
action "httpd is not running" /bin/false
httpdctl restart >/dev/null 2>&1
action "httpd is restart" /bin/true
mail -s "`uname -n`'s httpd restarted at `(date)`" 31333741@qq.com
exit 1
else
action "httpd is running" /bin/true
exit 0
fi
建议:生产环境推荐版本三,三重检测更可靠。
案例六:监控 httpd 服务 80 端口状态
根据端口判断服务是否启动,未启动则自动拉起并邮件告警。
#!/bin/bash
# 实时每隔3秒监控HTTP服务状态,服务异常输出报警信息并尝试启动
web=`netstat -ant | grep 80 | awk '{print $4}' | awk -F : '{print $4}'`
apachelog=/var/log/httpd/service.log
if [ "$web" = "80" ]; then
echo "HTTPD正在运行"
else
echo "Web服务重新启动"
echo "`date` Web服务重新启动" >> $apachelog
/etc/init.d/httpd start &> /dev/null
sleep 2
echo `date` 重新启动 | /usr/sbin/sendmail -v telephonenumber@139.com > /dev/null
fi
说明:将脚本加入 crontab 定时执行即可实现持续监控。换成其他服务端口也只需修改端口号和启动命令。
案例七:开机自动挂载本地 YUM 仓库
适用于无网络环境下快速搭建本地 YUM 源。
#!/bin/bash
# 自动搭建 yum 本地仓库
# 定义挂载函数
cdrom() {
mount /dev/cdrom /media/cdrom &> /dev/null
[ $? -eq 0 ] && echo "挂载成功"
}
# 创建挂载目录
[ -d /media/cdrom ] || mkdir /media/cdrom
# 如果已挂载则先卸载再重新挂载
mount | grep -q /dev/sr0
if [ $? -eq 0 ]; then
umount /dev/sr0
cdrom
else
cdrom
fi
# 备份原有 repo 文件
[ -d /etc/yum.repos.d/bak ] || mkdir /etc/yum.repos.d/bak
ls -l /etc/yum.repos.d/ | grep repo > /dev/null
if [ $? -ne 0 ]; then
echo "正在移动文件到备份目录"
mv /etc/yum.repos.d/*.repo bak
else
echo "文件已经移动过!"
fi
# 创建本地仓库配置文件
[ -e /etc/yum.repos.d/centos-media.repo ] || cat > /etc/yum.repos.d/centos-media.repo << 'EOF'
[media]
name=CentOS-$releasever - Media
baseurl=file:///media/cdrom/
gpgcheck=0
enabled=1
EOF
# 清除缓存并统计软件包
echo "清除yum缓存"
yum clean all &> /dev/null
echo "YUM已经搭建完成"
echo -n "共有软件包:"
yum repolist | tail -1 | awk -F':' '{print $2}'
# 写入 fstab 实现开机自动挂载
cat /etc/fstab | grep /dev/sr0 &> /dev/null
if [ $? -ne 0 ]; then
echo "正在写入开机自动挂载"
echo "/dev/sr0 /media/cdrom iso9660 defaults 0 0" >> /etc/fstab
fi
提示:执行完毕后即可使用
yum install安装软件,无需联网。
案例八:Shell 自动化管理账号脚本
帮助管理员通过菜单交互式地创建、删除、锁定、解锁用户。
#!/bin/bash
# 用户管理程序
# date: 2018-6-6
echo "====== 用户管理程序 ======"
echo "1. 创建用户"
echo "2. 删除用户"
echo "3. 锁定用户"
echo "4. 解锁用户"
echo "5. 退出脚本"
read -p "请输入您的操作选择(1-5):" sn
case $sn in
1)
read -p "请输入创建用户名:" nu
useradd $nu
echo "123456" | passwd --stdin $nu
[ $? -eq 0 ] && echo "用户 $nu 创建成功"
;;
2)
read -p "请输入要删除的用户名:" nl
userdel -r $nl
[ $? -eq 0 ] && echo "已成功删除 $nl 用户"
;;
3)
read -p "请输入要锁定的用户名:" use
STAT=$(passwd -S $use | awk '{print $2}')
if [ "$STAT" == "PS" ]; then
passwd -l $use
echo "用户 $use 已锁定"
elif [ "$STAT" == "LK" ]; then
echo "用户 $use 已经是锁定状态"
fi
;;
4)
read -p "请输入要解锁的用户名:" jie
STAT=$(passwd -S $jie | awk '{print $2}')
if [ "$STAT" == "LK" ]; then
passwd -u $jie
echo "用户 $jie 已解锁"
else
echo "用户 $jie 未被锁定"
fi
;;
5)
read -p "是否确认退出(yes):" tu
[ "$tu" == "yes" ] && exit 0
;;
*)
echo "无效选择"
;;
esac
注意:原文脚本中部分变量引用顺序有误(如先取
STAT再读use),整理版已修正执行顺序。
案例九:自动创建多个新用户并设置密码
批量创建用户是企业中最常见的运维需求之一,以下提供三个版本。
脚本一:批量创建 100 个用户
#!/bin/bash
for name in $(seq 1 100)
do
useradd "user$name"
if [ $? -eq 0 ]; then
echo "创建 user$name 成功!"
fi
done
脚本二:添加到指定组并设置密码
#!/bin/bash
groupadd users 2>/dev/null
for i in {1..100}
do
useradd user$i -g users
echo "user$i:password" | chpasswd
done
脚本三:简洁版(推荐)
#!/bin/bash
for i in {1..100}
do
useradd student$i
echo "123456" | passwd --stdin student$i
done
安全提醒:生产环境请使用随机密码(参考案例四),而非统一弱密码。
案例十:编写 Nginx 服务启动程序
源码安装的 Nginx 默认没有 service nginx start 支持,需要自行编写 init 脚本。提供两个版本。
脚本一:完整版(推荐)
1. 创建脚本并赋权
touch /etc/init.d/nginx
chmod +x /etc/init.d/nginx
2. 脚本内容
#!/bin/bash
# chkconfig: - 85 15
# description: Nginx server control script
# processname: nginx
# config file: /usr/local/nginx/conf/nginx.conf
# pid file: /usr/local/nginx/logs/nginx.pid
# source function library
. /etc/rc.d/init.d/functions
NGINX_NAME="nginx"
NGINX_PROG="/usr/local/sbin/nginx"
NGINX_PID_FILE="/usr/local/nginx/logs/nginx.pid"
NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"
NGINX_LOCK_FILE="/var/lock/subsys/nginx.lock"
# 检查当前用户
[ "$USER" != "root" ] && exit 1
start() {
status
if [[ $? -eq 0 ]]; then
echo "Nginx (PID $(cat $NGINX_PID_FILE)) already started."
return 1
fi
echo -n "Starting $NGINX_NAME: "
daemon $NGINX_PROG -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $NGINX_LOCK_FILE
return $retval
}
stop() {
status
if [[ $? -eq 1 ]]; then
echo "Nginx server already stopped."
return 1
fi
echo -n "Stopping $NGINX_NAME: "
killproc $NGINX_PROG
retval=$?
echo
[ $retval -eq 0 ] && rm -f $NGINX_LOCK_FILE
return $retval
}
restart() {
stop
sleep 1
start
}
reload() {
echo -n "Reloading $NGINX_NAME: "
killproc $NGINX_PROG -HUP
retval=$?
echo
return $retval
}
status() {
netstat -anpt | grep "/nginx" | awk '{print $6}' &> /dev/null
if [[ $? -eq 0 ]]; then
[[ -f $NGINX_LOCK_FILE ]] && return 0 || return 1
fi
return 1
}
_status() {
status
if [[ $? -eq 0 ]]; then
state=$(netstat -anpt | grep "/nginx" | awk '{print $6}')
echo "Nginx server status is: $state"
else
echo "Nginx server is not running"
fi
}
test() {
$NGINX_PROG -t -c $NGINX_CONF_FILE
return $?
}
case "$1" in
start) start ;;
stop) stop ;;
reload) reload ;;
restart) restart ;;
status) _status ;;
test) test ;;
*)
echo "Usage: { start | stop | reload | restart | status | test }"
exit 1
;;
esac
3. 注册为系统服务并设置开机启动
chkconfig --add nginx
chkconfig --level 3 nginx on
脚本二:精简版
1. 确保 Nginx 记录 PID
编辑 /usr/local/nginx/conf/nginx.conf,取消注释:
pid logs/nginx.pid;
2. 脚本内容
#!/bin/bash
# chkconfig: 2345 99 20
# description: Nginx Server Control Script
PROG="/usr/local/nginx/sbin/nginx"
PIDF="/usr/local/nginx/logs/nginx.pid"
case "$1" in
start)
if [ -f $PIDF ]; then
echo "Nginx 正在运行..."
else
$PROG
fi
;;
stop)
if [ -f $PIDF ]; then
kill -3 $(cat $PIDF)
rm -f $PIDF
else
echo "Nginx 已经停止"
fi
;;
restart)
$0 stop
$0 start
;;
reload)
if [ -f $PIDF ]; then
kill -1 $(cat $PIDF)
else
echo "Nginx 未运行,无法重载"
fi
;;
status)
if [ -f $PIDF ]; then
echo "Nginx 正在运行 (PID: $(cat $PIDF))"
else
echo "Nginx 已停止"
fi
;;
*)
echo "Usage: $0 (start|stop|restart|reload|status)"
exit 1
;;
esac
exit 0
3. 赋权并注册服务
chmod +x /etc/init.d/nginx
chkconfig --add nginx
chkconfig --level 3 nginx on
# 验证
service nginx status # Nginx 正在运行
service nginx stop # 停止
service nginx start # 启动
service nginx restart # 重启
总结速查表
| 案例 | 核心命令/技术 | 适用场景 |
|---|---|---|
| 一、日期计算 | date -d |
日志切割、定时任务日期处理 |
| 二、磁盘监控 | df -h + 重定向 |
磁盘空间巡检、日报生成 |
| 三、日志分析 | awk + sort + uniq -c |
访问日志统计、安全分析 |
| 四、随机密码 | /dev/urandom / $RANDOM / uuidgen |
批量建用户、安全初始化 |
| 五、HTTP 监控 | 进程/端口/URL 三重检测 | Web 服务高可用保障 |
| 六、端口监控 | netstat + 条件判断 |
通用服务存活检测 |
| 七、YUM 仓库 | 挂载 ISO + yum.repos.d |
离线环境软件安装 |
| 八、账号管理 | useradd / passwd -l/-u |
交互式用户运维 |
| 九、批量建用户 | for 循环 + chpasswd |
企业批量账号初始化 |
| 十、Nginx 脚本 | init 脚本 + chkconfig |
源码安装 Nginx 的服务化管理 |
提示:以上脚本建议在测试环境验证后再上生产,部分涉及系统级操作(如用户删除、服务重启)请谨慎执行。
浙公网安备 33010602011771号