文章目录
- 一、function函数
- 1.1 函数的定义使用
- 1.2 函数参数
- 1.2.1 脚本内传参
- 1.2.2 脚本外传参
- 1.3 引用局部变量
- 1.3.1 区分局部变量
- 1.3.2 全局变量在函数外
- 1.3.3 全局变量在函数体
- 1.3.4 函数体直接输出具体值
- 二、expect命令
- 2.1 常用命令
- 2.2 安装使用
- 2.3 例一
- 2.4 例二
- 2.5 例三
一、function函数
函数作用:
- 函数function是由若干条shell命令组成的语句块,定义函数后,可以通过引用函数实现代码重用和模块化编程,而不是重复写多段代码。
- 它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运 行,而是shell程序的一部分,定义函数只对当前的会话窗口有效,如果再打开一个窗口再定义另外一个函数,就对另一个窗口有效,两者互不影响。
- 函数和shell程序比较相似,区别在于以下两种:
- Shell程序在子Shell中运行。
- 而Shell函数在当前Shell中运行,因此在当前Shell中,函数可以对shell中变量进行修改。
1.1 函数的定义使用
基本了解:
- 函数由两部分组成:函数名和函数体。
- 引用函数直接写函数名即可。
注意事项:
- 可以function 【函数名】() 定义,也可以直接【函数名】() 定义。比如function qingjun(),也可以写成qingjun(),项目中大都使用简写定义函数。
- 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)
1.简写式。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
qingjun() {
echo 'hehe'
}
qingjun
2.全写式。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
function qingjun() {
echo 'hehe'
}
qingjun
1.2 函数参数
- 在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数…
1.2.1 脚本内传参
1.传入的第一个参数“start”对应函数里的$1,可选项有“start"、“stop”,若不是这两个选项则直接匹配*;传入的第二个参数“httpd”对应函数里的$2。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
my_service(){
case $1 in
"start")
echo "start $2"
;;
"stop")
echo "stop $2"
;;
*)
echo "Usage: service $2 start|stop"
;;
esac
}
my_service start httpd
1.2.2 脚本外传参
- 函数里的传参变量是根据变量在脚本里的位置来对应的,函数里的$1对应下面传参的第1个数或变量,不管你是不是$1(如下就是下面传入的参数$2对应函数里的$1),函数里的$2对应下面传参的第2个数或变量,以此类推。
- 函数里的变量只能在脚本里进行传参,若脚本里没有定义传参变量或脚本里没有直接传参,则直接匹配*。
1.例一,脚本里定义传参变量$2,$1,这两个变量值分别对应函数里的$1,$2,所以看到脚本里的传参时不要被名称给误导了,只需按照参数顺序依次对应函数里的$1,$2,$3,$4…即可。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
my_service(){
case $1 in
"start")
echo "start $2"
;;
"stop")
echo "stop $2"
;;
*)
echo "Usage: service $2 start|stop"
;;
esac
}
my_service $2 $1
2.例二。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
my_service(){
case $1 in
"start")
echo "start $2"
;;
"stop")
echo "stop $2"
;;
*)
echo "Usage: service $2 start|stop"
;;
esac
}
my_service $1 $2
3.例三,脚本不传参,则直接匹配*。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
my_service(){
case $1 in
"start")
echo "start $2"
;;
"stop")
echo "stop $2"
;;
*)
echo "Usage: service $2 start|stop"
;;
esac
}
my_service
1.3 引用局部变量
- 局部变量使用local来定义,比如本地变量是a=10,定义成局部变量为local a=10。
- 局部变量只对当前代码段生效。
1.3.1 区分局部变量
1.定义本地变量a=10对全局生效,函数里定义局部变量a=20只对当前函数代码块生效,所以在最后echo $a时,用的是全局变量a=10。那为什么没有把函数里的echo $a打印出来?是因为没有引用函数,所以不执行函数里的操作。
2.此时引用函数,则执行函数体,会把函数里的echo $a打印出来,引用的是函数里的局部变量local a=20。
1.3.2 全局变量在函数外
1.此时定义第2个全局变量a=30,这样最后一行的echo $a输出的是全局变量a=30,因为后者全局变量会把前者覆盖,而不会覆盖函数里的局部变量a=20。
1.3.3 全局变量在函数体
- 当函数里即存在局部变量,也存在全局变量时,需要看两者的先后顺序,因为顺序不同覆盖效果也不同。
- 若全局变量在局部变量后面,则覆盖函数内的局部变量。
- 若全局变量在局部变量前面,则覆盖函数外的全局变量。
1.如下示例,有两个全局变量a=10和a=30,后者在函数内,此时a=30会覆盖局部变量a=20,函数外的全局变量不受影响,最后调用函数输出的是30。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
a=10
my_service(){
local a=20
a=30
echo $a
}
my_service
echo $a
2.当全局变量在局部变量前面时,会覆盖函数外的全局变量,函数内的局部变量不受影响。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
a=10
my_service(){
a=30
local a=20
echo $a
}
my_service
echo $a
1.3.4 函数体直接输出具体值
1.当函数体不存在局部变量时,此时会直接输出函数体结果,即时存在全局变量也是覆盖函数外的全局变量。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
a=10
my_service(){
a=30
echo 50
}
my_service
echo $a
2.此时函数内添加局部变量,需要看添加位置,若是加在全局变量前面,则会被函数内的全局变量覆盖,但最终引用函数输出的值是具体值50,最后一行输出的值是函数外的全局变量值10。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
a=10
my_service(){
local a=20
a=30
echo 50
}
my_service
echo $a
3.当添加的局部变量在函数里的全局变量后面,则不会受影响,最后一行的echo $a是用的函数里的全局变量a=30,将函数外的a=10覆盖了。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
a=10
my_service(){
a=30
local a=20
echo 50
}
my_service
echo $a
二、expect命令
基本了解:
- 若需要交互式的命令,比如ssh到其他机器,需要输入密码,scp命令这种需要交互式的输入密码则可以用expect。
- expect是一个自动化交互套件,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信。
expect自动交互流程:
- spawn启动指定进程 ——> expect获取指定关键字 ——>send向指定程序发送指定字符 ——> 执行完成退出
2.1 常用命令
子命令 | 释义 |
---|---|
spawn | 交互程序开始后面跟命令或者指定程序 |
expect | 获取匹配信息匹配成功则执行expect后面的程序动作 |
send exp_send | 用于发送指定的字符串信息 |
exp_continue | 在expect中多次匹配就需要用到 |
send_user | 用来打印输出相当于she11中的echo |
exit | 退出expect脚本 |
eof | expect执行结束 退出 |
set | 定义变量 |
puts | 输出变量 |
set_timeout | 设置超时时间 |
2.2 安装使用
- 需要提前安装expect,之后才能在脚本中引用子命令。
1.安装。
yum install -y expect
2.查看。
2.3 例一
1.远程到192.168.130.161主机上,并且执行命令df -Th查看磁盘资源。
[root@localhost ~]# cat qingjun.sh
#!/usr/bin/expect ##固定写法,使用expect执行脚本。
spawn ssh root@192.168.130.161 df -Th ##spawn固定写法,后面跟需要交互的命令,df -Th是交互完成后要执行的命令。
expect "*password" ##期望匹配“*password”
send "citms@123\n" ##发送密码,意思是写交互时要写入的密码。
expect eof ##期望结束。
2.4 例二
- 例一写法有个弊端,就是当期望太多时,写出来的代码很长,所以可以使用以下这种写法。
[root@localhost ~]# cat qingjun.sh
#!/usr/bin/expect
spawn ssh root@192.168.130.161 df -Th
expect {
"*yes/no*" {send "yes\n"; exp_continue} ##第一个期望,期望匹配“*yes/no*”时输入的值为“yes”,exp_continue代表继续。
"*password:*" {send "redhat\n"} ##第二个期望,期望匹配“*password:*”时输入的值为“redhat”,\n表示回车,不然输入密码后不会往后执行。
}
expect eof
2.5 例三
- openssl签发CA证书。
[root@localhost ~]# cat qingjun.sh
#!/bin/bash
if [ $UID -ne 0 ];then
echo "请以管理员身份运行此脚本。"
exit 120
fi
if [ ! -d /etc/pki/CA ];then
mkdir -p /etc/pki/CA
fi
cd /etc/pki/CA
if [ ! -d private ];then
mkdir -p private
fi
(umask 077;openssl genrsa -out private/cakey.pem 2048)
/usr/bin/expect <<EOF
spawn openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 365
expect {
"*code" {send "CN\n"; exp_continue}
"Province" {send "HB\n"; exp_continue}
"*city" {send "WH\n"; exp_continue}
"*Company" {send "www.example.com\n"; exp_continue}
"*section" {send "www.example.com\n"; exp_continue}
"*hostname" {send "www.example.com\n"; exp_continue}
"*Address" {send "1@2.com\n"}
}
expect eof
EOF
mkdir certs newcerts crl &>/dev/null
touch index.txt && echo 01 > serial
cd
(umask 077;openssl genrsa -out httpd.key 2048)
/usr/bin/expect <<EOF
spawn openssl req -new -key httpd.key -days 365 -out httpd.csr
expect {
"*code" {send "CN\n";exp_continue}
"*Province" {send "HB\n";exp_continue}
"*city" {send "WH\n";exp_continue}
"*Company" {send "www.example.com\n";exp_continue}
"*section" {send "www.example.com\n";exp_continue}
"*hostname" {send "www.example.com\n";exp_continue}
"*Address" {send "1@2.com\n";exp_continue}
"*password" {send "\n";exp_continue}
"An*" {send "\n"}
}
expect eof
EOF
/usr/bin/expect <<EOF
spawn openssl ca -in httpd.csr -out httpd.crt -days 365
expect {
"Sign*" {send "y\n";exp_continue}
"*commit" {send "y\n"}
}
expect eof
EOF