在写脚本的时候,会经常用到某些算法、命令集等,如果每次都要重新再写一遍,就非常浪费时间,所以就需要用到函数来解决这个问题了。而且有时候会遇到交互式的情况,那么该怎么办呢?except就是用来解决这种情况的。那么接下来就看一下函数及expect的用法吧。j_0007.gif

一、函数

   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了

wKiom1m888KyoDfuAAA_3D2Xh3s125.jpg

注意:如果函数体与{}写在同一行,那么大括号里两边都要有空格,且最后的空格之前要有分号。

4、local 变量名  

表示设置本地变量,只在函数体内部起作用

比如,当前shell中name的值为li,而在函数中定义local name=chen,那么不影响当前shell

wKioL1m885SC9JPaAAAqF5r027s758.jpg 

5、在命令行定义好的函数是不能修改的,只能删除重建,或者直接使用同一个函数名,重新写函数体 ,那么就会覆盖原来的函数体了。

wKiom1m888Lh_fVRAAAssgCX2dM980.jpg 

6、函数名不要跟现有的别名,现有的命令等冲突。如果冲突,系统会认为你是要执行该命令,而不是定义函数,就会报错

wKioL1m885TwflQgAAAcm89T7yk588.jpg 

7、函数相当于命令,可以使用反引号``来引用其执行结果

wKiom1m888Khb3njAAAcKwtvnA0751.jpg 

8、函数如果是在命令行直接写的,那么只在当前终端能用,如果写在文件中,那么都可以用

wKiom1m888KQbD3QAAEomJ3VHKo399.jpg

9、函数中可以使用别名,脚本中不能用别名

wKioL1m885XQV8KSAAAeuklCAlI827.jpg 

wKioL1m885Wia7GYAAAnzHxjKUM753.jpg 

10、在函数中一般不用exit退出,会直接退出当前shell,可以使用return退出函数,并且还可以自定义返回值。

wKiom1m888OxWgJgAAAWcTCrY3c738.jpg 

wKiom1m888OzphgYAAAV5DNuZqY167.jpg 

11、/etc/init.d/functions该文件存放着大量的函数的定义

如果别的函数或者脚本需要用到该文件里的函数,那么直接使用. /etc/init.d/functions调用这个文件,再调用其中的函数即可。当然自定义的函数也可以写入其中,或者自己再建一个文件存放自定义的函数,那么用的时候直接调用文件,就不用每次都要定义函数了。

wKioL1m885XgNiWGAAAokKNL29Y765.jpg 

12、函数的递归调用,即自己调用自己。每调用一次就开一个子进程,所以使用函数的时候注意递归次数。

      了解了函数的作与用法之后,来写个脚本试试吧j_0069.gif


编写脚本/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"}'

wKioL1m89Ivi3--3AAAdb7nbmkY652.jpg

  -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”,并换行

wKiom1m89LmDUem7AAAcQDrxH74938.jpg 

5、多分支模式语法:

   比如expect

            expect "hi" { send "You said hi\n" } \

             "hehe" { send Hehe yourself\n" } \

              "bye" { send Good bye\n" }     

表示匹配hi,hello,bye任意字符串时,执行相应输出。

wKiom1m89Lnj7Iu2AAAnuXILbLM059.jpg 

示例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

wKioL1m89IyR_g_DAAC0TFa14po422.jpg 

示例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

wKioL1m89IzDASSkAAAr9Lh_AmA168.jpg 

示例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

wKiom1m89LrRFpsfAAAx1FldT0o300.jpg 

示例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

wKioL1m89IzADEf4AACx27slYkA238.jpg 

示例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

wKiom1m89L2wfgIlAACYpXnSHnw490.jpg 

   以上就是博主要跟大家分享的东西,希望能对大家有所帮助。欢迎留言,共同探讨。

j_0055.gif