shell脚本系列
shell脚本系列
案例一:shell脚本指定日期减去一天
如果只减去一天的话,直接写就可以了。
#date -d"yesterday 20150401" +%Y%m%d
如果要减去几天,还可以这样写,如果用负数是往前数,
#date -d"10 day ago 2015-04-01" +%Y-%m-%d
在指定的日期上加上指定的小时
[dc@dc010.tj.momo.com init_env]$ date -d "20150416 12 3 hour" +"%Y%m%d%H"
2015041615
在指定的日期上减去指定的小时
[dc@dc010.tj.momo.com init_env]$ date -d "20150416 12 -1 hour" +"%Y%m%d%H"
2015041611
在指定的日期上加上指定的分钟
[dc@dc010.tj.momo.com init_env]$ date -d "20150416 12:20 10 minute" +"%Y%m%d%H%M"
201504161230
date -d参数可以根据当前日期获取更多我们需要的日期。
本月和下月
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 -d'+1 day'
date +%Y%m%d --date "+1 day"
date +%Y%m%d --date='+1 day'
指定月份
date -d 1May
现在:
date -d now
其他
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” //显示下一年的日期
案例二:shell脚本获取当前日期和时间及磁盘使情况
习题分析
本题有两个核心知识点:
1. 如何自动表示当天的日期
2. 磁盘使用情况
打印日期的命令为 date,示例命令如下:
# date
2017 年 12 月 20 日 星期三 16:26:55 CST
而题目中要求的格式为应该是:2017-12-20,date 命令是有这样的功能的,示例命令如下:
# 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. shell 中反引号可以表示一个命令的结果,通常给变量赋值,示例命令如下:
# 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 ##其中/etc/nofile 是不存在的,所以会报错
ls: 无法访问/etc/nofile: 没有那个文件或目录
/etc/passwd
# ls /etc/passwd /etc/nofile > /tmp/log 2>/tmp/error
# cat /tmp/log
/etc/passwd
# cat /tmp/error
ls: 无法访问/etc/nofile: 没有那个文件或目录\
案例三:shell统计ip访问情况并分析访问日志
题目要求
有日志 1.log,部分内容如下:
112.111.12.248 – [25/Sep/2013:16:08:31 +0800]formula-x.haotui.com“/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]xyzdiy.5d6d.com“/attachment.php?aid=4554&k=9ce51e2c376bc861603c7689d97c04a1&t=1334564048&fid=9&sid=zgohwYoLZq2qPW233ZIRsJiUeu22XqE8f49jY9mouRSoE71″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; .NET CLR 2.0.50727)”
统计出每个 IP 的访问量有多少
习题分析
这种分析日志的需求,在平时工作中很常见,而且找运维工作时的笔试题里面出现频率也非常多。
根据日志内容,可以看到 IP 地址就是第一段内容,所以只需要把 1.log 的第一段给过滤出来,然后近一步统计每一个 IP 的量即可。
过滤第一段,使用 awk 就可以很容易得到,而统计每个 IP 的访问量则需要排序然后再计算数量,
排序使用 sort 命令,统计每个 IP 访问量用 uniq。
习题答案
awk '{print $1}' 1.log |sort -n |uniq -c |sort -n
答案解析
1. awk 命令在分段方面还是比较有优势的,这里的{print $1}讲第一段打印出来,awk 可以用-F 指定分隔符,如果不指定分隔符,默认就以空白字符(比如空格、Tab 等),本题中,IP 地址就是在第一段。
2. sort 命令是排序的命令,-n 选项表示以数字的形式排序,如果不加-n,则以 ASCII 排序,本题中的 IP 地址以数字的形式排序更容易区分。
3. uniq 命令是用来去重复的,一个文本中如果有多行内容是一模一样的,使用 uniq 命令就可以把相同内容的行给删除掉,只留一行。而-c 选项的作用是计算重复的行数,所以在此题中使用 uniq -c 正好可以计算 IP 地址的访问数量。不过,大家一定要注意,uniq 去重的前提是首先要排序。
4. 本题答案里最后没得 sort -n 意思是按访问量大小来排序,请求量越大的 IP 排在越后面,如果要想排在前面,可以加一个-r 选项,即 sort –nr
案例四:Shell脚本生成随机密码
生成随机密码(urandom版本)
#!/bin/bash
#Author:丁丁历险(Jacob)
#/dev/urandom文件是Linux内置的随机设备文件
#cat /dev/urandom可以看看里面的内容,ctrl+c退出查看
#查看该文件内容后,发现内容有些太随机,包括很多特殊符号,我们需要的密码不希望使用这些符号
#tr -dc '_A-Za-z0-9'
#该命令可以将随机文件中其他的字符删除,仅保留大小写字母,数字,下划线,但是内容还是太多
#我们可以继续将优化好的内容通过管道传递给head命令,在大量数据中仅显示头10个字节
#注意A前面有个下划线
tr -dc '_A-Za-z0-9'
生成随机密码(字串截取版本)
#!/bin/bash
#Author:丁丁历险(Jacob)
#设置变量key,存储密码的所有可能性(密码库),如果还需要其他字符请自行添加其他密码字符
#使用$#统计密码库的长度
key="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
num=${#key}
#设置初始密码为空
pass=''
#循环8次,生成8为随机密码
#每次都是随机数对密码库的长度取余,确保提取的密码字符不超过密码库的长度
#每次循环提取一位随机密码,并将该随机密码追加到pass变量的最后
for i in {1..8}
do
index=$[RANDOM%num]
pass=$pass${key:$index:1}
done
echo $pass
生成随机密码(UUID版本,16进制密码)
#!/bin/bash
uuidgen
4.生成随机密码(进程ID版本,数字密码)
#!/bin/bash
echo $$
案例五:shell脚本实现定时监控http服务的运行状态
注意:监控方法可以为端口、进程、URL模拟访问方式,或者三种方法综合。
说明:由于截止到目前仅讲了if语句,因此,就请大家用if语句来实现。
[root@localhost scripts]# cat apachemon
#!/bin/sh
. /etc/init.d/functions
HTTPPRONUM=`ps -ef|grep http|grep -v grep|wc -l`
#if [ $HTTPPRONUM -lt 1 ];then
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]# ps -ef |grep http |grep -v grep
[root@localhost scripts]# apachemon
httpd is not running [失败]
httpd is restart [确定]
[root@localhost scripts]# ps -ef|grep http|grep -v grep
root 5845 1 1 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5852 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5853 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5854 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5855 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5856 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5857 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5858 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
apache 5859 5845 0 15:59 ? 00:00:00 /usr/sbin/httpd -k restart
脚本改进
[root@localhost /]# echo oldboytest >/var/www/html/index.htm
[root@localhost /]# wget –quiet –spider http://10.0.0.161/index.htm
[root@localhost /]# echo $?
0
[root@localhost /]# ll index.htm
ls: index.htm: 没有那个文件或目录
隔离
[root@localhost scripts]# cat apachemon1
#!/bin/sh
#created by oldboy 20110523
. /etc/init.d/functions
#HTTPPRONUM=`ps -ef|grep http|grep -v grep|wc -l` #=====>这个是基于http方式进行判断
wget –quiet –spider http://10.0.0.161/index.htm #=====>这个是基于WGET URL方式进行判断
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)`” mail@qq.com
exit 1
else
action “httpd is running” /bin/true
exit 0
fi
真正使用时,有些输出是不需要的就去掉
[root@localhost scripts]# cat apachemon1
#!/bin/sh
#created by oldboy 20110523
#
. /etc/init.d/functions
wget –quiet –spider http://10.0.0.161/index.htm #=====>这个是基于WGET URL方式进行判断
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
多条件判断的写法
[root@localhost scripts]# cat apachemon1
#!/bin/sh
#created by oldboy 20110523
#
. /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
#if [ "$RETVAL" != "0" -o "$HTTPPORTNUM" != "1" -o "$HTTPPRONUM" \< "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
案例六:shell脚本监控httpd服务80端口状态
这里是举例监控httpd服务端口状态,根据端口判断服务器是否启动,如果没有启动则脚本自动拉起服务,如果服务正在运行则退出脚本程序;如果换成别的服务端口也可以,但是脚本程序需要做调整。
#!/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
案例七:shell实现开机自动挂载本地YUM仓库程序
shell实现开机自动挂载本地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
[ -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 ] || echo "[media]
name=CentOS-$releasever - Media
baseurl=file:///media/cdrom/
gpgcheck=0
enabled=1" > /etc/yum.repos.d/centos-media.repo
echo "清除yum缓存"
yum clean all &> /dev/null
echo "YUM已经搭建完成"
echo -n "共有软件包:"
yum repolist | tail -1 | awk -F':' '{print $2}'
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
案例八:Shell自动化管理账号脚本
该脚本目的帮助管理员创建账号、删除账号、锁定账号、解锁账号。
#!/bin/bash
#filename:
#author:
#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
if [ '$?' == '0' ];
then
echo "用户已经创建成功"
exit
fi
;;
2)
read -p "请输入要删除用户名:" nl
userdel $nl
echo "已经删除$nl用户"
if
[ $? -ne 0 ];
then
echo "成功删除"
fi
;;
3)
STAT=$(passwd -S $use | awk '{print $2}')
read -p "锁定用户" use
if [ '$STAT' == "PS" ];
then
passwd -l $use
fi
if [ '$STAT' == "LK" ];
then
echo "已经锁定用户"
exit
fi
;;
4)
read -p "解锁用户" jie
echo $jie
if [ '$STAT' == "LK" ];
then
passwd -u $jie
fi
if [ '$STAT' == "LK" ];
then
echo "已经解锁用户"
exit
fi
;;
5)
if [ $sn == 5 ];
then
read -p "是否退出(yes)" tu
if [ $tu == yes ];
then
exit
fi
fi
esac
案例九:shell脚本自动创建多个新用户,并设置密码
此脚本是用来批量创建用户并设置用户密码,在企业用非常实用。
脚本一
#!/bin/bash
for name in $( seq 1 100 )
do
useradd "user$name"
if [ $? -eq 0 ];then
echo -e "\n创建 "user$name" 成功!"
fi
done
添加100用户在users组,并设置密码为user
脚本二
i=1
for (1..100)
do
groupadd users
adduser user$i -g users
echo user | passwd "user$1" --stdin
i=$( $i + 1)
done
添加100用户并设置密码
脚本三
#!/bin/bash
for i in {1..100}
do
useradd student$i
echo "123456" | passwd --stdin student$i
done
案例十:shell编写nginx服务启动程序
使用源码包安装的Nginx没办法使用"service nginx start"或"/etc/init.d/nginx start"进行操作和控制,所以写了以下的服务控制脚本,该脚本有如下选项:
start 启动
stop 停止
reload 重载
restart 重启
status 状态
test 检查配置文件
脚本一
创建脚本文件并添加执行权限
touch /etc/init.d/nginx
chmod +x /etc/init.d/nginx
编写脚本内容
#!/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
#
# eastmoney public tools
# version: v1.0.0
# create by XuHoo, 2016-9-14
#
# 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"
# check current user
[ "$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 $"Stoping $NGINX_NAME: "
killproc $NGINX_PROG
retval=$?
echo
[ $retval -eq 0 ] && rm -f $NGINX_LOCK_FILE
return $retval
}
restart() {
stop
sleep 1
start
retval=$?
return $retval
}
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
if [[ -f $NGINX_LOCK_FILE ]]; then
return 0
else
return 1
fi
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
retval=$?
return $retval
}
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
将脚本添加到系统服务并设置开机启动
chkconfig --add nginx
chkconfig --level 3 nginx on
脚本二
[root@localhost ~]# cd /usr/local/nginx/conf/
[root@localhost conf]# ls
fastcgi.conf fastcgi_params koi-utf mime.types nginx.conf scgi_params uwsgi_params win-utf
fastcgi.conf.default fastcgi_params.default koi-win mime.types.default nginx.conf.default scgi_params.default uwsgi_params.default
备份主配置文件
[root@localhost conf]# cp nginx.conf nginx.conf.origin
[root@localhost conf]# vim nginx.conf
#去除#pid logs/nginx.pid;前面#号
[root@localhost conf]# netstat -anpt | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 19108/nginx
[root@localhost conf]# kill -3 19108
[root@localhost conf]# netstat -anpt | grep 80
[root@localhost conf]# nginx
[root@localhost conf]# netstat -anpt | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 19864/nginx
[root@localhost conf]# cd ../logs/
[root@localhost logs]# ls
access.log error.log nginx.pid
[root@localhost logs]# cat nginx.pid
19864
编辑写服务脚本
#!/bin/bash
#chkconfig: 2345 99 20
#description:Nginx Server Control Scripts shell
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正在运行"
else
echo "Nginx停止"
fi
;;
*)
echo "Usage: $0 (start|stop|restart|reload|status)"
exit 1
esac
exit 0
添加执行权限
[root@localhost ~]# chmod +x /etc/init.d/nginx
#将脚本添加到系统服务并设置开机启动
[root@localhost ~]# chkconfig --add nginx
添加为服务启动项
[root@localhost ~]# chkconfig --list nginx
nginx 0:关闭 1:关闭 2:启用 3:启用 4:启用 5:启用 6:关闭
[root@localhost ~]# chkconfig --level 3 nginx on
测试脚本是否能够执行
[root@localhost ~]# service nginx start
Nginx正在运行…
[root@localhost ~]# service nginx restart
[root@localhost ~]# service nginx stop
[root@localhost ~]# service nginx stop
Nginx正在停止…
[root@localhost ~]# service nginx start
[root@localhost ~]# service nginx status
Nginx正在运行
--... ...--
iaoexl at outlook dot com
-------------------------------------------------------------
鱼跃此时海,花开彼岸天。只缘有余庆,翩翩在此间。