在写脚本的时候,会经常用到某些算法、命令集等,如果每次都要重新再写一遍,就非常浪费时间,所以就需要用到函数来解决这个问题了。而且有时候会遇到交互式的情况,那么该怎么办呢?except就是用来解决这种情况的。那么接下来就看一下函数及expect的用法吧。
一、函数
1、定义函数的定义:
f_name()
{
...函数体...
}
2、函数体:
函数体就是一堆命令的集合
3、函数的调用:
直接写函数名就是调用该函数
4、函数的删除:
unset f_name
函数说明:
1、函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。
2、它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分
3、函数和shell程序比较相似,区别在于:
Shell程序在子Shell中运行,不会影响父shell。
而函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改。
比如当前shell中变量name的值是chen,而在函数中定义name=li,那么调用函数之后,当前shell中name的值就变成li了
注意:如果函数体与{}写在同一行,那么大括号里两边都要有空格,且最后的空格之前要有分号。
4、local 变量名
表示设置本地变量,只在函数体内部起作用
比如,当前shell中name的值为li,而在函数中定义local name=chen,那么不影响当前shell
5、在命令行定义好的函数是不能修改的,只能删除重建,或者直接使用同一个函数名,重新写函数体 ,那么就会覆盖原来的函数体了。
6、函数名不要跟现有的别名,现有的命令等冲突。如果冲突,系统会认为你是要执行该命令,而不是定义函数,就会报错
7、函数相当于命令,可以使用反引号``来引用其执行结果
8、函数如果是在命令行直接写的,那么只在当前终端能用,如果写在文件中,那么都可以用
9、函数中可以使用别名,脚本中不能用别名
10、在函数中一般不用exit退出,会直接退出当前shell,可以使用return退出函数,并且还可以自定义返回值。
11、/etc/init.d/functions该文件存放着大量的函数的定义
如果别的函数或者脚本需要用到该文件里的函数,那么直接使用. /etc/init.d/functions调用这个文件,再调用其中的函数即可。当然自定义的函数也可以写入其中,或者自己再建一个文件存放自定义的函数,那么用的时候直接调用文件,就不用每次都要定义函数了。
12、函数的递归调用,即自己调用自己。每调用一次就开一个子进程,所以使用函数的时候注意递归次数。
编写脚本/root/bin/copycmd.sh,要求:
(1) 提示用户输入一个可执行命令名称
(2) 获取此命令所依赖到的所有库文件列表
(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;如:
/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:如:
/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit
#!/bin/bash
. /etc/init.d/functions
echo "目标目录是:/app"
[ -d /app ]||mkdir /app
cpcmd(){
if which $needcmd &>/dev/null;then
local cmd=`which --skip-alias $needcmd`
local dir=`dirname $cmd`
[ -d /app$dir ]||mkdir -p /app$dir
if [ -f /app$cmd ];then
echo "$cmd 已存在"
else
cp $cmd /app$dir&&echo `action "$cmd" true`
fi
elif [ "$needcmd" == "quit" ];then
exit
else
echo "命令不存在或者该命令是内部命令或者该命令是别名"
fi
}
cpso(){
if which $needcmd &>/dev/null;then
local so=`ldd $(which --skip-alias $needcmd)|egrep -o "/.* "`
for i in $so ;do
local sodir=`dirname $i`
[ -d /app$sodir ]||mkdir -p /app$sodir
if [ -f /app$i ];then
echo "$i 已存在"
else
cp $i /app$sodir&&echo `action "$cmd" true`
fi
done
fi
}
until [[ "$needcmd" == "quit" ]];do
read -p "请输入需要复制的命令(quit退出): " needcmd
cpcmd
cpso
done
二、expect
expect默认是没有安装的,需要安装yum install expect
1、expect作用:
自动化地把交互式的提交变成非交互式的。
可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率
2、expect 语法:
expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
选项:
-c:从命令行执行expect脚本,默认expect是交互地执行的
示例:expect -c ‘expect "hi" {send "you said hi\n"}‘
-d:可以输出调试信息,即显示详细的过程
比如expect -d ssh1.exp表示执行ssh1.exp登陆到别的终端,并且显示详细的信息。而且登陆之后,在该终端执行的每个操作都会重新再显示一遍。
3、expect中相关命令
spawn:启动新的进程
send:用于向进程发送字符串
expect:从进程接收字符串
interact:允许用户交互
exp_continue 需要匹配多个字符串时,在执行动作后加此命令
这几个命令会在下面的示例中详细说明
4、expect最常用的语法(tcl语言:模式-动作)单一分支模式语法:
比如expect “hi” {send “You said hi\n"}
表示匹配到hi后,会输出“you said hi”,并换行
5、多分支模式语法:
比如expect
expect "hi" { send "You said hi\n" } \
"hehe" { send “Hehe yourself\n" } \
"bye" { send “Good bye\n" }
表示匹配hi,hello,bye任意字符串时,执行相应输出。
示例1:
cat ssh1.exp
#!/usr/bin/expect
spawn ssh 192.168.80.128 ----->表示启动新进程,即执行ssh命令
expect {
"yes/no" { send "yes\n";exp_continue } ---->表示匹配到yes/no时,就输入yes并
回车,exp_continue表示后面还有字符串需要匹配
"password" { send "123456\n" } ---->表示匹配到password时,就输入123456并回车
}
Interact ----->允许用户交互,也就是说成功登陆之后可以继续在该终端 继续操作,而不直接退出
执行:ssh1.exp
示例2:在expect脚本使用变量
cat ssh2.exp
#!/usr/bin/expect
set ip 192.168.8.100 ----->设置变量ip=192.168.8.100
set user root ---->设置变量user=root
set password 123456 ---->设置变量password=123456
set timeout 10 ----->设置超时时间为10秒,超过10秒没执行成功就终止进程
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
Interact
执行:ssh2.exp
示例3:引用位置参数
cat ssh3.exp
#!/usr/bin/expect
set ip [lindex $argv 0] ----->将第一个参数的值赋值给变量ip
set user [lindex $argv 1] ----->将第二个参数的值赋值给变量user
set password [lindex $argv 2] ----->将第三个参数的值赋值给变量password
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
执行:ssh3.exp 192.168.80.128 root 123456
示例4:执行多个命令
cat ssh4.exp
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd haha\n" } ----->创建用户haha
expect "]#" { send "echo magedu |passwd --stdin haha\n" }----->给该用户设置密码
send "exit\n" ----->退出连接
expect eof ------>结束expect,相当于退出ssh连接后换行的作用
执行:ssh4.exp 192.168.80.128 root 123456
示例5:shell脚本调用expect
cat ssh5.sh
#!/bin/bash
ip=$1
user=$2
password=$3
expect <<EOF ------->将下面的内容重定向到expect,直到读到EOF结束
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n" }
expect "]#" { send "echo magedu |passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF
执行:ssh5.sh 192.168.8.100 root magedu
以上就是博主要跟大家分享的东西,希望能对大家有所帮助。欢迎留言,共同探讨。
原文地址:http://13150617.blog.51cto.com/13140617/1965903