一、shell脚本编程学习概述
(一)、学习shell脚本原因
提升工作效率
减少重复工作
完成批量操作
节省人力成本
(二)、学习shell必备知识
1、熟练使用编辑软件
vim
2、熟练使用常用命令
150个常用命令
三剑客命令
3、熟练使用系统符号
系统常用符号
系统通配符号
系统正则符号
(三)、学习shell方法技巧
(一)、技巧方法
会看脚本
模仿编写
(二)、高手核心
量的积累,产生质的变化
(三)、学习误区
依赖高手,拿来主义
二、shell脚本概念
Shell是一个命令解释器,它的作用是解释执行用户输入的命令及程序等
(一)、解释器工作方式
采用交互式方式进行解释
采用非交互式方式进行解释
(二)、shell种类
/bin/sh ---> 是bash一个软链接
/bin/bash ---> linux系统默认使用shell解释器
/sbin/nologin ---> 无法登陆访问shell
/usr/bin/csh
/usr/bin/rsh
三、shell脚本需掌握内容
(一)、掌握脚本基本语法
1、变量设定
普通变量
定义方式
先写变量名称,紧接着是 "=" ,最后是值。中间无任何空格
调用变量
通过echo命令加上 $变量名,即可输出变量的值。
双引号,以防止出错变量的值一般要加上
变量永久生效
将变量设置编写到文件中
(/etc/profile /etc/bashrc ~/.bashrc ~/.bash_profile)
环境变量
定义方式
export info=“I am HQ”
调取变量
echo $info
永久生效:
将变量设置编写到文件中
(/etc/profile /etc/bashrc)
条件表达式
if判断语法
单分支语句
if [ ]
then #则
命令
fi
双分支语句
if [ ]
then #则
命令
else #否则
命令
fi
多分支语句
if [ ]
then
elif [ ]
then
elif [ ]
then
else
fi
for循环
while循环
case语句
函数语法规范
数组
(二)、定义变量规范:
变量不能使用数字开头
定义变量时“=”两边不能有空格
变量建议由字母与“_”组成
变量设置见名知其义
1、养成脚本编写规范
脚本保存目录规范
将脚本文件统一保存在指定目录中
2、脚本编写规范
1、一个规范的Shell脚本在第一行会指出由哪个程序(解释器)来执行脚本中的内容
2、在shell脚本中,跟在 # 后面的内容表示注释,用来对脚本进行注释说明,
注释部分不会被当做程序来执行,仅仅是给开发者和使用者看的,系统解释器是看不到的,更不会执行
3、Shell脚本的开头会加版本、版权等信息
# Date:16:29 2018-10-20 --> 脚本编写时间
# Author: Create by xiaoxie --> 脚本作者
# Description: This script function is …… -->脚本作用
4、在shell脚本中尽量不用中文注释,尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰
5、Shell脚本的命名应以.sh为扩展名 例如:This is a premium name
6、成对的符号应尽量一次性写出来,然后退格在符号内增加内容,以防止遗漏。这些成对的符号包括: {}、[]、‘’、“” 等
7、中括号[]两端至少要有1个空格,因此,键入中括号时即留出空格[ ],
然后在退格键入中间内容,并确保两端都至少由一个空格
8、对于流程控制语句,应一次性将格式写完,再添加内容
如:一次性完成for循环语句的格式
9、通过缩进让代码更易读
10、对于常规变量的字符串定义变量值应加双引号,并且等号前后不能有空格,
需要强引用的,则用单引号(‘’),如果是命令的引用,则用反引号(``)
11、脚本中的单引号、双引号及反引号必须为英文状态下的符号
3、脚本运行方法
方法一:利用bash解释器命令运行脚本
[root@web01 /server/scripts/sh]# bash test01.sh
方法二:利用脚本绝对路径运行脚本
[root@web01 /server/scripts/sh]# /server/scripts/sh/test01.sh
方法三:利用 . 或者 source执行脚本
[root@web01 /server/scripts]# . /server/scripts/test01.sh
[root@web01 /server/scripts]#source /server/scripts/test01.sh
说明:三种方式区别
方法一 和 方法二 都是在子shell中执行脚本
方法三在父shell中进行运行
四、shell变量的设置
(一)、变量的赋值方法
方法一:直接赋值
a=1
方法二:传参赋值
a=$1
方法三:交互式赋值
read 变量名
read -p "提示信息" 变量名
read -t “输入超时时间” 变量名
(二)、脚本中特殊变量
位置变量
$0 用于获得脚本名称信息
应用示例
echo "Usage: $0 {请写入学生年龄和姓名}"
echo "学生名字: $1"
echo "学生年龄: $2"
$n 脚本的第n个传参数,n表示从1-9,大于9参数数量 使用${10}
应用示例
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10}
$# 位置参数的数量
应用示例
[ $# -eq 2 ] || echo "Usage: $0 {请写入学生年龄和姓名}"
$* 所有位置参数的内容,加引号时表示将多个参数作为一个整体
$@ 所有位置参数的内容,加引号时会将多个参数作为个体
不加双引号没有任何区别,将所有参数信息全部显示
加上双引号, 在循环体中,$* 会将所有参数看成一个整体,$@ 会将所有参数看成多个个体
状态变量
$? 获取上一个命令执行结果 成功用0 失败用非0
示例应用
[ $# -ne 1 ] && echo "Usage: $0 {请输入一个域名信息!}" && exit 2
ping -c 2 $1 &>/dev/null
[ $? -eq 0 ] && echo "This web_name $1 is ok. " || echo "This web_name $1 is error
$$ 获取一个脚本执行PID信息
示例应用
# $$ 获取脚本执行进程信息
echo $$ >/tmp/test.pid
$! 获取上一个程序或脚本后台运行的pid信息
示例应用
[root@web01 scripts ]# sh test04.sh & --- 让脚本在后台运行
[1] 118411
[root@web01 scripts ]# echo $! --- 获取上一个在后台运行脚本pid信息
118411
[root@web01 scripts ]# jobs --- 查看在后台运行的程序信息
[1]+ 运行中 sh test_ip.sh &
[root@web01 scripts ]# fg 1 --- 恢复后台运行程序到前台
$_ 获取脚本的最后一个参数信息 == esc .
应用示例
[root@web01 scripts 12:37:06]# sh test03.sh oldgirl olddog oldboy
oldgirl olddog oldboy
[root@web01 scripts 12:37:33]# echo $_
oldboy
变量子串
${paramter} 返回变量信息内容
应用示例
[root@web01 scripts ]# oldboy=linux
[root@web01 scripts ]# echo $oldboy
linux
[root@web01 scripts ]# echo ${oldboy}
linux
[root@web01 scripts ]# echo $oldboyisok
[root@web01 scripts ]# echo ${oldboy}isok
linuxisok
${#paramter} 返回变量字符长度
应用示例
OLDBOY="I am oldboy teacher"
echo ${#OLDBOY}
19
已知一个变量 OLDBOY="I am oldboy teacher",
问变量信息字符数量是多少, 如何统计
方法一:echo $OLDBOY|wc -L
方法二:expr length "$OLDBOY"
方法三:echo $OLDBOY|awk '{print length}'
方法四:echo ${#oldboy}
已知一个变量 OLDBOY="I am oldboy teacher my name is HQ"
请找出字符串长度小于3的信息
方法一:
oldboy="i am oldboy teacher my name is hq"
for a in $oldboy
do
if [ ${#a} -lt 3 ]
then
echo $a
fi
done
方法二: echo $OLDBOY|xargs -n1|awk '{if(length<3)print}'
方法三:echo $OLDBOY|awk '{for(i=1;i<=NF;i++)if(length($i)<3)print $i}'
方法四:echo $OLDBOY|egrep -wo "[a-Z]{1,3}"
${paramter:offset} 在变量中,从指定字符位置开始提取子串到结尾信息
应用示例
[root@web01 ~]# echo $oldboy
I am oldboy tnux ro r python eacher my name is sa gfd
[root@web01 ~]# echo ${oldboy:2}
am oldboy tnux ro r python eacher my name is sa gfd
[root@web01 ~]# echo ${oldboy:0}
I am oldboy tnux ro r python eacher my name is sa gfd
${paramter:offset:length} 在变量中,从指定字符位置开始提取子串到指定位置结束
应用示例
[root@web01 scripts ]# echo $OLDBOY
I am oldboy teacher my name is HQ
在变量中,从指定字符位置开始提取子串到指定位置结束
[root@web01 scripts ] # echo ${OLDBOY:2:2}
am
补充: 子串中offset信息可以从0开始
[root@web01 scripts ]# echo ${OLDBOY:0:4}
I am
[root@web01 scripts ]# echo ${OLDBOY::4}
I am
${paramter#word} 从变量开头开始删除最短匹配的word子串信息
应用示例
[root@web01 ~]# echo $oldboy
I am oldboy tnux ro r python eacher my name is sa gfd
[root@web01 ~]# echo ${oldboy#I*d}
boy tnux ro r python eacher my name is sa gfd
[root@web01 ~]# echo ${oldboy#I*t}
nux ro r python eacher my name is sa gfd
[root@web01 ~]# echo ${oldboy#a*t}
I am oldboy tnux ro r python eacher my name is sa gfd
此方法必须从第一个字符写起
${paramter##word} 从变量开头开始删除最长匹配(贪婪匹配)的word子串信息
应用示例
${paramter%word} 从变量结尾开始删除最短匹配的word子串信息
应用示例
${paramter%%word} 从变量结尾开始删除最长匹配的word子串信息
应用示例
${paramter/string/replace} 使用replace信息替换string字符串, 并且只替换第一个匹配的信息
应用示例
${praamter//string/replace} 使用replace信息替换string字符串, 但是会将所有信息全部替换
应用示例
变量替换
${paramter:-word} 当调取变量信息值为空时或未赋值, 就返回word字符串信息
应用示例
作用
如果变量未定义,则返回备用字符串信息,防止变量为空值或未定义导致异常
${paramter:=world} 当调取变量信息值为空时或未赋值,则设置指定字符串为新的变量值
应用示例
作用
如果变量未定义,用指定字符串直接给变量赋值
${paramter:?word} 当调取变量信息值为空时或未赋值,指定为赋值的错误提示信息
应用示例
作用
如果变量未定义,利用指定字符串进行错误提示说明
${paramter:+word} 当调取变量信息值为空时或未赋值,不做任何处理,否则word字符串将替代变量值
应用示例
作用
如果变量未定义, 调取变量信息时, 不会有任何显示
如何变量已定义, 调取变量信息时, 会显示指定字符串信息
?word与+word总结
?word: 变量未定义提示错误信息; 变量已定义显示变量信息
+word: 变量未定义不做任何处理; 变量已定义显示提示信息
(三)、变量算法
算术运算符
算术运算命令
(()) 实现整数数值运算
应用1:简单数值运算
[root@oldboy ~ ]# echo $((4*4))
16
[root@oldboy ~ ]# echo $((4/4))
1
[root@oldboy ~ ]# echo $((2**3))
8
应用2:识别变量做运算
[root@oldboy ~ ]# a=10
[root@oldboy ~ ]# echo $((a+1))
11
[root@oldboy ~ ]# echo $((a*2))
20
应用3:用于数值比较判断
[root@oldboy ~ ]# echo $((3<8))
1
[root@oldboy ~ ]# echo $((3>8))
0
[root@oldboy ~ ]# echo $((8=8))
-bash: 8=8: attempted assignment to non-variable (error token is "=8")
[root@oldboy ~ ]# echo $((8==8))
1
[root@oldboy ~ ]# echo $((7==8))
0
[root@oldboy ~ ]# echo $((7!=8))
1
[root@oldboy ~ ]# echo $((3<8 && 5==5))
1
[root@oldboy ~ ]# echo $((3>8 && 5==5))
0
[root@oldboy ~ ]# echo $((3>8 || 5==5))
1
[root@oldboy ~ ]# echo $((3>8 || 5==6))
0
比较信息成立会使用返回值1表示
比较信息不成立会使用返回值0表示
应用4:实现自增/自减运算
自增运算
a=a+1
a++:是先执行表达式后再自增,执行表达式时使用的是a的原值
++a:是先自增再执行表达示,执行表达式时使用的是自增后的a
自减运算
a=a-1
a--:是先执行表达式后再自增,执行表达式时使用的是a的原值
--a:是先自增再执行表达示,执行表达式时使用的是自增后的a
let 实现整数数值运算
应用1:简单整数运算
[root@web01 ~]# let i=5*9
[root@web01 ~]# echo $i
45
应用2:识别变量信息做运算
[root@web01 ~]# i=2
[root@web01 ~]# let i=i+2
[root@web01 ~]# echo $i
4
expr 实现整数运算
应用1:做数值信息简单运算
[root@web01 ~]# expr 2 \* 3
6
[root@web01 ~]# expr 2 + 3
5
应用2:判断输入参数信息是否为整数
[root@web01 ~]# i=5
[root@web01 ~]# expr $i+5
5+5
[root@web01 ~]# expr $i + 5
10
[root@web01 ~]# echo $?
0
[root@web01 ~]# i=oldboy
[root@web01 ~]# expr $i + 9
expr: 非整数参数
[root@web01 ~]# i=1.5
[root@web01 ~]# expr $i + 9
expr: 非整数参数
运算符两侧须有空格
应用3:统计字符串长度
[root@web01 ~]# oldboy="I am oldboy teacher"
[root@web01 ~]# expr length "$oldboy"
19
应用4:验证文件的扩展名
#!/bin/bash
if expr "$1" : ".*\.jpg" &>/dev/null
then
echo "这个传参文件是一个图片文件"
else
echo "这个传参文件不是图片信息"
fi
bc Linux中的计算器程序
seq -s+ 10 | bc
awk 实现数值运算
awk 'BEGIN{print 5*10-3+6}'
declare 实现数值运算
a=5;declare -i a=a+10;echo $a
五、shell脚本编写逻辑信息
(一)、逻辑判断语句
1、shell脚本条件表达式
条件表达式
test
说明:利用test进行表达式书写进行判断条件信息
规范:test命令和""之间至少有一个空格
[ ]
说明:利用中括号 进行表达式书写进行判断条件信息
规范:[]的边界和内容之间至少有一个空格
[[ ]]
说明:利用双中括号 进行表达式书写进行判断条件信息
规范: [[]]的边界和内容之间至少有一个空格
(())
说明: 利用双小括号 进行表达式书写进行判断条件信息
规范:(())(双小括号)两端不需要有空格
条件表达式特殊书写方式
[ ] && {
命令1
命令2
}
(二)、编写脚本格式说明
①. 开头编写解释器信息
#!/bin/bash
②. 开头编写脚本的注释
author 作者
data 日期
desc 脚本作用
(三)、if条件语句
单分支条件语句
语法
if [ 条件 ]
then #则
命令
fi
案例:输入2个数字,比较大小
双分支条件语句
语法
if [ 条件 ]
then #则
命令
else #否则
命令
fi
案例:判断用户并下载软件
#!/bin/bash
if [ $USER == "root" ]
then
yum ‐y install vsftpd
else
echo "您不是管理员,没有权限安装软件"
fi
多分支条件语句
语法
if 条件判断;then
命令
elif 条件判断;then
命令
else
命令
fi
(四)、结构条件语句(case语句)
case结构条件语句说明:
相当于多分支的if/elif/else条件语句, 但是它比这些条件语句看起来更规范更工整
常被应用于实现系统服务启动脚本等企业应用场景中
case结构条件语句语法:
case "变量" in
值1)
指令1...
;;
值2)
指令2...
;;
*)
指令3...
esac
case结构语句执行流程
case结构语句测试练习
①. 测试case语句打印水果菜单信息
. /server/scripts/sh/fruit_fun.sh
men
while true
do
read -p "please input inquire fruit: " num
case $num in
1|apple|a)
echo -e "\033[31m apple price is 10 \033[0m"
;;
2|strawberry|s)
echo -e "\033[32m strawberry price is 20 \033[0m"
;;
3|pear|p)
echo -e "\033[33m pear price is 30 \033[0m"
;;
4|grape|g)
echo -e "\033[34m grape price is 40 \033[0m"
;;
5|help|h)
men
;;
6|quit|q)
exit 1
;;
*)
echo "please input inquire fruit: "
;;
esac
done
(五)、逻辑循环语句
for循环语句
概念说明
for循环语句主要用于执行次数有限的循环,而不是用于守护进程及无限循环
语法说明
根据变量数值进行循环
for 变量名 in 变量取值列表; do 指令 ;done
根据判断条件进行循环
for ((exp1;exp2;exp3));do 指令 ;done
嵌入式循环
情况一: 爷爷--爸爸--儿子
#!/bin/bash
for a in {1..3}
do
echo $a
for b in {a..c}
do
echo $a$b
for c in {A..C}
do
echo $a$b$c
done
done
done
情况二: 父亲--二子1/二子2
#!/bin/bash
for a in {1..3}
do
echo $a
for b in {a..c}
do
echo $a$b
done
for c in {A..C}
do
echo $a$b$c
done
done
(六)、while循环语句
语法
方法一:只要条件为真, 就会一直循环下去
while true
do
echo oldboy
done
方法二:条件判断
while ((条件语句)) [条件语句]
do
动作
done
#!/bin/bash
i=0
while [ $i -le 10 ]
do
echo oldboy $i
let i++
done
方法三:读取文件循环
#!/bin/bash
while read 变量名
do
echo $变量名
done < user.txt
测试练习
1) 循环输出数值信息
#!/bin/bash
i=0
while [ $i -le 10 ]
do
echo oldboy $i
let i++
done
2) 循环读取文件内容
while read line
do
echo $line
done
调试测试脚本
sh -x 脚本
在windows写脚本注意
dos2unix 转码文件
六、脚本函数功能
(一)、脚本函数概念
函数是命令的集合,完成特定功能的代码块,代码块可以实现重复使用
(二)、脚本函数作用
①. 相同的程序段定义成函数, 可以减少整个程序的代码量, 提升开发效率
②. 增加程序的可读性 易读性 提升管理效率
③. 实现程序功能模块化 使得程序具备通用性(可移植性)
(三)、脚本函数语法
标准语法格式:
function 函数名(){ }
简化语法格式:
function 函数名 { }
函数名(){ }
系统自带函数
/etc/init.d/functions
(四)、脚本函数调用
①. 调用函数时,函数名前的function和函数名后的小括号都不要带
②. 函数的定义必须在要执行的程序前面定义或加载
③. shell执行系统中各程序顺序 系统别名--函数--系统命令--可执行文件
④. 函数执行时, 会和调用它的脚本共用变量, 也可以为函数设置局部变量及特殊位置参数
⑤. 在shell函数里面, return命令的功能与exit类似, return的作用是退出函数, 而exit是退出脚本文件
⑥. return语句会返回一个退出值给调用函数的当前程序, 而exit会返回一个退出值给执行程序的当前shell
⑦. 如果将函数存放在独立的文件中, 被脚本加载使用时, 需要使用source 或 "." 来加载
⑧. 在函数内一般使用local定义局部变量, 这些变量离开函数后就会消失
(五)、脚本函数传参
①. shell的位置参数($1 $2 $# $* $? $@)都可以作为函数的参数来使用
②. 此时父脚本的参数临时地被函数参数所掩盖或隐藏
③. $0比较特殊, 仍然是父脚本的名称
④. 当函数执行完成时, 原来的命令行脚本的参数即可恢复
⑤. 函数的参数变量是在函数体里面定义的
(六)、脚本函数分离
将编写的函数信息放入到指定的函数库文件中, 进行加载函数库文件, 实现函数信息分离
函数定义变量
脚本和函数中同时定义变量, 各自调用使用自己的变量信息
脚本和函数中一方定义变量, 各自调用使用对方的变量信息
函数的返回值
根据return返回值信息, 判断函数命令是否执行正确
七、shell脚本编程扩展说明
(一)、shell脚本控制指令
循环控制指令
break n
跳出本次循环体,继续执行之后操作
n 表示跳出循环的层数, 如果省略n, 表示跳出整个循环
continue n
跳出本次循环,继续执行下次循环
n 表示退出到第n层继续循环, 如果省略n, 表示跳出本次循环, 忽略本地循环的剩余代码
退出脚本指令
exit n
退出当前shell程序, n为上一次程序执行的状态返回值, n可以省略, 在下一个shell里可通过$? 接收exit n的n值
退出函数指令
return n
用于在函数里作为函数的返回值, 以判断函数执行是否正确, 在下一个shell里可通过 $? 接收 return n的值
(二)、shell脚本数组概念
shell数组概念介绍
1) 数据就是元素的集合, 把有限个元素(变量或字符内容)用一个名字来命名, 然后用编号对它们进行区分
2) 元素集合的名称, 就成为数组名
3) 用于区分不同内容的编号就称为数组下标
4) 组成数组的各个元素(变量)称为数组的元素, 有时称为下标变量
shell数组作用说明
可以将多个变量信息进行汇总定义, 避免单独定义的麻烦
可以进行数据信息统计
shell数组实践说明
普通数组定义
方法一:利用小括号定义数组
数组名称=(元素1 元素2 元素3)
方法二:利用小括号设置键值对
数组名称=([key1]=value1 [key2]=value2 [key3]=value3)
方法三:分别定义数组及元素信息
数组名称[下标]=元素
方法四:利用执行命令结果设置数组信息
array=(`命令信息`)
aaray=($(命令信息))
关联数组定义
declare -A 数组名 #指定某一个数组为关联数组
shell数组调用
查看数组所有元素信息
echo ${array[*]}
查看数组所有元素信息
echo ${array[*]}
echo ${array[@]}
查看数组指定元素信息
echo ${array[n]}
PS:元素未指定下标时,默认从"0"开始排序
查看数组元素长度信息
echo ${#array[*]}
echo ${#array[@]}
查看数组所有元素的索引信息
echo ${!array[*]}
普通数组与关联数组区别:
普通数组: 表示只能以数字作为索引(下标), 调取元素值信息
关联数组: 表示只能以数字或字符串作为索引(下标)
数组信息的扩展操作
输出数组长度信息(获取数组元素数量)
echo ${#array[*]}
添加数组数值信息
array[3]=oldbaby
删除数组数值信息
unset array[1]
数组数值信息的截取
echo ${array[*]:1开始截取位置:截取位数}
数组数值信息替换
echo ${array[*]/被替换数值/替换后数值}
数组的应用实践
遍历数组数值信息
方法一:获取所有信息遍历
#!/bin/bash
array=(
oldboy
olddog
oldgirl
oldbaby
)
for i in ${array[*]}
do
echo $i
done
方法二:利用索引信息遍历
#!/bin/bash
array=(
oldboy
olddog
oldgirl
oldbaby
)
for i in ${!array[*]}
do
echo ${array[$i]}
done
(三)、加快脚本运行效率
实现方法:{循环体}&
#!/bin/bash
for ip in 10.0.{0..63}.{1..254}
do
{ ping -c 3 -W 3 $ip &>/dev/null
if [ $? -eq 0 ]
then
echo $ip is online
else
echo $ip is offline
fi } &
done
八、shell脚本信号控制
(一)、脚本信号控制作用
在脚本执行过程中,可能会被一些键盘操作快捷方式所打断
影响脚本运行,脚本控制信号可以屏蔽这些信号
(二)、脚本信号
trap -l (查看所有信号)
HUP(1):挂起信号(终端或用户退出断开时自动触发信号)
INT(2):中断(键盘快捷键"ctrl+c"而产生的信号)
QUIT(3):退出(键盘快捷键"ctrl+\"而产生的信号)
ABRT(6):中止(因严重错误所产生的信号)
TERM(15):终止(系统关机时所产生的信号)
TSTP(20):停止进程运行(键盘快捷键"ctrl+z"所产生的信号)
(三)、识别信号命令 trap
命令语法:trap 命令 信号信息
命令作用
根据指定信号,完成指定操作
根据指定信号,进行信号屏蔽
九、shell脚本自动应答
(一)、自动应答作用
实现自动化管理,自动应答,自动响应
(二)、自动应答原理
第一步:运行一个程序或命令(spawn 命令信息)
第二步: 识别产生信息关键字 expect 捕获关键字 {send 应答信息}
第三步: 根据识别关键做处理 send 应答信息
(三)、自动应答脚本编写方式
第一步:下载安装expect软件程序
yum -y install expect
第二步:编写自动应答脚本
(脚本名称定义:脚本名称.exp)
#!/usr/bin/expect
# #!/usr/bin/expect 为自动化应答脚本声明信息
if { $argc != 2 } {
#自动应答脚本if判断格式 if { 条件表达式 } { 运行命令 }
# $argc 相当于 $#
puts "please input two paramter"
# puts 相当于 echo
exit 1
}
set ip [lindex $argv 0]
#自动化应答脚本位置变量设置方式 set 变量名 [lindex $argv n]
set cmd [lindex $argv 1]
set pass "123456"
#自动应答脚本变量设置方式 set 变量名 "变量值"
spawn ssh root@$ip $cmd
#运行的命令,$ip 调用变量
expect {
#捕获关键字
"yes/no" {send "yes\r";exp_continue}
#关键字信息 {send 应答信息;应答此条,自动跳到下一条交互处}
"password" {send "$pass\r"}
}
expect eof
#结束应答标志
第三步:运行自动应答脚本
(脚本运行命令:expect 脚本名称)
expect expect_test.exp 10.0.0.31 "df -h"
十、编写服务运行脚本使服务归systemctl管理
例:sersync服务
第一步:编写服务运行脚本
vim /server/scription/rsnc.sh
#!/bin/bash
. /etc/init.d/functions
case $1 in
start)
ps -ef | grep -v grep | grep sersync &>/dev/null
if [ $? -eq 0 ]
then
action "sersync is running... " /bin/true
else
/usr/local/sersync/sersync -dro /usr/local/sersync/confxml.xml &>/dev/null
[ $? -eq 0 ] && action "sersync start is " /bin/true || action "sersync start is " /bin/false
fi
;;
stop)
ps -ef | grep -v grep | grep sersync &>/dev/null
if [ $? -eq 0 ]
then
pid=$(ps -ef | grep -v grep | grep sersync | awk '{print $2}')
kill -9 $pid &>/dev/null
ps -ef | grep -v grep | grep sersync &>/dev/null
[ $? -ne 0 ] && action "sersync stop is " /bin/true || action "sersync stop is " /bin/false
else
action "sersync is not running ..." /bin/false
fi
;;
*)
echo "请输入正确命令"
esac
第二步:给脚本添加执行权限
chmod +x rsnc.sh
第三步:编写systemctl单元文件
/usr/lib/systemd/system/
[Unit] ---- 确认服务启动时依赖关系
# 单元文件描述说明
Description=OpenSSH server daemon
# 定义服务相关手册文档信息
Documentation=man:sshd(8) man:sshd_config(5)
# 定义服务运行依赖关系, 在指定服务启动后, 在启动相应服务
After=network.target sshd-keygen.service
# 定义服务运行依赖关系, 在指定服务启动前, 先启动相应后
Before=xxx
# 定义服务运行依赖关系, 需要和其他一些服务同时启动
Requires=
# 定义服务运行依赖关系, 希望有些服务和当前服务一起运行
Wants=sshd-keygen.service
[Service] ---- 确认服务启动命令和脚本信息 nginx
# 向后面参数发出通知, 启动服务程序
Type=notify
# 在服务启动时加载一个服务启动相关文件
EnvironmentFile=/etc/sysconfig/sshd
# 定义启动服务命令和脚本信息
ExecStart=serync start
ExecReload=sersync reload
KillMode=process
Restart=on-failure
RestartSec=42s
[Install] ---- 定义服务开机自动运行级别
WantedBy=multi-user.target
第四步:让systemctl加载新的单元文件
systemctl daemon-reload