Shell脚本
(1)用途:
使用简单,是Shell命令的集合
运行节省时间
可实现批量管理,自动化
批量处理减少出错概率
(2)shell概述
shell:命令解释器,也是一个程序
种类:sh , bash ,ksh ,csh。。。
bash的特性:
a 历史记录 ----> 用户行为升级
b 别名 ----> 企业垃圾桶,rm --》mv
c 补全 ----> 命令($PATH),目录
d 支持通配符 ---->*,[],[^]
e 前后台作业 ---->jobs, & ,bg,fg
f 运行脚本
系统shell类型
[root@nfs01 ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
默认shell
[root@nfs01 ~]# echo $SHELL
/bin/bash
bash安全性:
[root@nfs01 ~]# env x='(){:;}; echo be careful ' bash -c "echo this is a test"
this is a test
##如果返回
be careful
this ia a test
则需要升级系统。
[root@nfs01 ~]# yum -y updata bash^C
[root@nfs01 ~]# rpm -qa bash
bash-4.2.46-31.el7.x86_64
(3)shell的建立
a
登录(交互)式Shell和非登录(交互)式Shell
登录式Shell:环境变量文件加载顺序 /etc/profile(/etc/profile.d/*),/.bash_profile,/.bashrc,/etc/bashrc
登录式shell场景:输入用户名和密码,“su - test002”
非登录式Shell:环境变量文件加载顺序 /.bash_profile,/.bashrc,/etc/bashrc ;
非登录式shell场景:“su test002”,定时计划任务,ansible的playbook。
b
shell执行:加载环境变量ENV,该变量制定了环境文件(/etc/profile(/etc/profile.d/*),/.bash_profile,/.bashrc,/etc/bashrc) —》执行内容
(4)shell的执行
a
通过sh或者bash命令执行
b
直接运行,脚本必须要有可执行权限
c
通过. 或者source 执行,在文件中的变量,函数的返回值将会加载到父及bash环境中。
d
通过重定向,说明bash和sh是可以接受标准输入的
(6)shell脚本的注释
单行注释:#
多行注释::<<BLOCK
BLOCK
(7)shell脚本规范
shell变量
查看:env: 系统的全局变量
set: 所有的全局变量
declare: 所有导入的全局变量和函数
局部变量的定义
'' : 强引
"" :弱引
`` : 执行Shell命令
(8)shell中常见的固定性的内容的生成
加密码:
Centos 6:
grub-md5-cryp
Centos 7:
grub2-mkpasswd-pbkdf2
grub-md5-crypt >> /etc/grub.conf
grub-md5-crypt |tee -a /etc/grub.conf
md5文件校验码:
[root@bogon test]# md5sum passwd1
56cf56372303c1c769ec0d030144e60c passwd1
[root@bogon test]# md5sum passwd
911bc5a50ff7cb7e2de6addb28c94abe passwd
生成自然数:
方法一:
实例:
#!/bin/bash
read -p "请输入起始值:" sta
read -p "请输入终止值:" sto
for i in `eval echo {$sta..$sto}`
do
echo $i
done
总结:bash不会解析多层变量,eval命令能解析多层变量。
[root@bogon test]# set 11 22 33 44
[root@bogon test]# echo $4
44
[root@bogon test]# echo $# #打印参数的个数
4
[root@bogon test]# echo \$$#
$4
[root@bogon test]# eval echo \$$#
44
方法二
seq命令用于产生从某个数到另外一个数之间的所有整数。
seq [选项]... 尾数
seq [选项]... 首数 尾数
seq [选项]... 首数 增量 尾数
-f, --format=格式 使用printf 样式的浮点格式
-s, --separator=字符串 使用指定字符串分隔数字(默认使用:\n)
-w, --equal-width 在列前添加0 使得宽度相同
[root@nfs01 tmp]# seq -f "%3g" 8 12
8
9
10
11
12
[root@nfs01 tmp]# seq -f "%03g" 8 12
008
009
010
011
012
[root@nfs01 tmp]# seq -w 8 12
08
09
10
11
12
[root@nfs01 tmp]# seq -s" " -f"str%02g" 9 11
str09 str10 str11
[root@nfs01 tmp]# seq -s"`echo -e "\t"`" 9 11
9 10 11
[root@nfs01 tmp]# seq -s"`echo -e "\n"`" 9 11
19293949596979899910911
[root@nfs01 tmp]# seq -s"=" 9 11
9=10=11
echo的参数等信息说明
echo参数选项 | 说明 |
---|---|
-n | 不换行输出内容 |
-e | 解析转义字符 |
转义字符: | |
\n | 换行 |
\r | 回车 |
\t | 制表符 |
\b | 退格 |
\v | 纵向制表符 |
生成随机数
方法一: $RANDOM
shell脚本----生成随机数
#!/bin/bash
function rand(){
min=$1
max=$(($2-$min+1))
num=$(($RANDOM+1000000000)) #增加一个10位的数再求余
echo $(($num%$max+$min))
}
read -p "please input your num of start:" sta
read -p "please input your num of end:" sto
rnd=$(rand $sta $sto)
echo $rnd
exit 0
方法二:openssl
[root@nfs01 ~]# openssl rand -base64 8 |md5sum |cut -c 1-12
d2ddb347a589
[root@nfs01 ~]# openssl rand -base64 8 |cksum |cut -c 1-10 #最大十位
3441980797
生成UUID:
[root@nfs01 ~]# uuidgen
b9db1d55-411d-429f-86ab-39c1a7746abb
[root@nfs01 ~]# cat /proc/sys/kernel/random/uuid
ef2d4611-4bf8-4735-96f7-b8e7a342ff14
生成MAC:
[root@nfs01 ~]# echo "00:0c:29:`openssl rand -hex 3 | sed 's/\(..\)/\1:/g; s/.$//'`"
00:0c:29:48:7b:8f
(9)命令排序
; 拼接多个命令没有逻辑关系
[root@bogon test]# ll 123;sh useradd.sh
&& 拼接多个命令,有逻辑关系
[root@bogon test]# sh useradd.sh && ll 123
[root@bogon test]# ll 123 && sh useradd.sh
|| 拼接命令,有逻辑关系,
[root@bogon test]# ll 123 || sh useradd.sh
注意:
command & 后台执行
command &>/dev/null 混合重定向(标准输出1,错误输出2)
command1 && command2 命令排序,逻辑判断
(10)位置变量:
$0,
$1,$2 …
{10},${11} … # 接收脚本或者函数的位置参数。
$0 文件名,若执行脚本时带有路径,会将路径和将本名同事输出。
$# 表示参数的个数
Shell进程的特殊状态变量说明
$?:获取执行上一个指令的执行状态返回值
$$:获取当前执行的shell脚本的进程号(PID)
$!:获取上一个在后台工作的进程的进程号
$_:获取在此之前执行的命令或脚本的最后一个参数
在企业场景下,"$?"返回值的用法如下:
(1)判断命令,脚本或函数等程序是否执行成功
(2)若在脚本中调用执行"exit数字",则会返回这个数字给"$?"变量
(3)如果是在函数里,则通过"return 数字"把这个数字一函数返回值的形式传给"$?"。
(11)dirname,basename
[root@bogon test]# dirname /root/test/var2.sh
/root/test
[root@bogon test]# basename /root/test/var2.sh
var2.sh
实例:
#!/bin/bash
echo $0
echo "`dirname $0`" #dirname 打印路径
echo "`basename $0`" #basename 打印文件名
(12)状态变量
(1)判断上一条命令是否执行成功,成功则返回0,不成功则返回非0;
(2)获取脚本的exit的退出码
(3)获取的是函数的返回值
实例:监控web服务状态是否正常
思路
a
判断进程:[root@bogon test]# ps -ef |grep httpd
[root@bogon test]# killall -0 httpd
b
判断端口:[root@bogon test]# netstat -tunalp |grep 80
c
判断链接:[root@bogon test]# curl 127.0.0.1
[root@bogon test]# cat monitor_httpd.sh
#!/bin/bash
service=httpd
while true
do
killall -0 $service &>/dev/null
#curl 127.0.0.1 &>/dev/null
#`ps -ef |grep httpd |grep -v grep` &>/dev/null
#`netstat -tulanp |grep 80` &>/dev/null
if [ $? -eq 0 ]
then
echo "httpd is up ..."
else
echo "httpd is down ..."
fi
sleep 1
done
EXEC
功能
:exec命令能够在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该进程(也就是最初的shell)就终止了
(14)常见的内置命令
a :
echo
-e :解析转义字符
-n :不换行输出
rnd=$(rand $1 $2)
echo -ne "随机数是: \t$rnd"
echo -e "\t请拿好..."
exit 50
b:
exec :在不启动子进程的前题下运行命令,执行完后杀死当前进程。
c:
read -p :读取用户输入的内容
d:
shift :移动位置参数
实例:企业垃圾桶参数偏移
[root@bogon test]# cat rm.sh
#!/bin/bash
[ -d /dev/mynull ] || mkdir /dev/mynull
shift
mv $1 /dev/mynull
e:
exit n (数字)
$?
(13)字符串操作
定义:
[root@bogon test]#a=daahufsuufsdghfgdiha
[root@bogon test]#a="cnsjv dsjf dshs"
[root@bogon test]#a='afnkjs$a##w*l'
查看:
[root@bogon test]# echo $a
[root@bogon test]# echo ${a}
afhkjsfjsdfjdskfasli$alkdahkjf
获取字符串长度:
[root@bogon test]# echo ${#a}
截取子串:
[root@bogon test]# echo ${a:4} #从第5个位置开始取子串
[root@bogon test]# echo ${a:4:1} #从第5个位置开始取1个字符
[root@bogon test]# echo ${a#w*l} #从左向右最短匹配
[root@bogon test]# echo ${a##w*l} #从左向右最长匹配
[root@bogon test]# echo ${a%l*x} #从右往左最短匹配
[root@bogon test]# echo ${a%%l*x} #从右往左最长匹配
[root@bogon test]# echo ${a/l*x/00000} #最大范围匹配到的字符替换
[root@bogon test]# echo ${a/l/0} #从左向右替换第一个匹配到的字符
[root@bogon test]# echo ${a//l/0} #从从往右替换所有匹配到的字符
[root@bogon test]# cat file3.sh
#!/bin/bash
#"如何修改shell中的for循环,使其不以空格分割。而是以换行"
#IFS:
IFS_old=$IFS
IFS=$'\n'
for i in `ip a |grep -E '\<inet\>'` #for 循环默认以空格分割,---""
do
#echo $IFS
#echo $i
j=${i#*t}
echo ${j%%/*}
#echo ${j%%s*o}
done
IFS=$IFS_old
(14)字符串的特殊变量扩展
echo ${parameter:-word} :如果parameter为空,则输出word,parameter本身没有发生变化;如果不为空输出parameter的值。
echo ${parameter:=word} :如果parameter为空,则输出word,parameter已经赋予word的值;如果不为空输出parameter的值。
echo ${parameter:?word} :如果parameter为空,则输出word,此时word将是错误输出的提示,echo $? 返回值为1;如果不为空输出parameter的值。
echo ${parameter:+word} :如果parameter为空,则输出空,如果不为空输出word,parameter本身没有发生变化。
定时计划任务坑:
坑1:[root@server02 ~]# vim /var/spool/cron/root 这样做,权限不对,正确的方法是crontab -e;.vimrc.bak;
-rw------- 1 root root 9 6月 23 18:35 root
坑2:计划任务在执行时,是在自己的家目录下执行的,所以脚本中一定要写绝对路径。
[root@bogon test]# crontab -e
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
#
0 */1 * * * . /etc/profile;/root/test/ping_log.sh
#c
0 0 */1 * * . /etc/profile;/root/test/ping_log1.sh
(17)shell中的数值计算
a:
(()) :既能做数值运算,又能做数值比较
[root@bogon test]# a=$((1+1))
[root@bogon test]# echo a
a
[root@bogon test]# echo $a
2
if ((1>2))
then
echo "ok"
else
echo "not ok"
fi
b:
let :数值运算
[root@bogon test]# let a=1+2
[root@bogon test]# echo $a
3
c:
expr :数值运算(判断是否为数字),字符串对比(判断两字符串是否一致),求字串长度
[root@bogon test]# expr 1 + 2
3
[root@bogon test]# expr 1 \* 2
2
[root@bogon test]# expr 1 \/ 2
0
[root@bogon test]# expr 1 \% 2
1
字符串匹配。匹配的字符串以“:”相隔,匹配则为真,反之,为假。
[root@bogon test]# expr "123" : "124" &>/dev/null
[root@bogon test]# echo $?
1
[root@bogon test]# expr "123" : "123" &>/dev/null
[root@bogon test]# echo $?
0