Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1827898
  • 博文数量: 636
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 3950
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-06 21:58
个人简介

博客是我工作的好帮手,遇到困难就来博客找资料

文章分类

全部博文(636)

文章存档

2024年(5)

2022年(2)

2021年(4)

2020年(40)

2019年(4)

2018年(78)

2017年(213)

2016年(41)

2015年(183)

2014年(66)

我的朋友

分类: 系统运维

2015-01-16 16:01:58

一、概述

        我们通过Shell可以实现简单的控制流功能,如:循环、判断等。但是对于需要交互的场合则必须通过人工来干预,有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能。而Expect就使用来实现这种功能的工具。

        Expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。Expect的作者Don Libes在1990年 

      开始编写Expect时对Expect做有如下定义:Expect是一个用来实现自动交互功能的软件套件 (Expect [is a] software 

      suite for automating interactive tools)。使用它系统管理员 

      的可以创建脚本用来实现对命令或程序提供输入,而这些命令和程序是期望从终端(terminal)得到输入,一般来说这些输入都需要手工输入进行的。 

      Expect则可以根据程序的提示模拟标准输入提供给程序需要的输入来实现交互程序执行。甚至可以实现实现简单的BBS聊天机器人。 :)

        Expect是不断发展的,随着时间的流逝,其功能越来越强大,已经成为系统管理员的的一个强大助手。Expect需要Tcl编程语言的支持,要在系统上运行Expect必须首先安装Tcl。

        二、Expect工作原理

        从最简单的层次来说,Expect的工作方式象一个通用化的Chat脚本工具。Chat脚本最早用于UUCP网络内,以用来实现计算机之间需要建立连接时进行特定的登录会话的自动化。

        Chat脚本由一系列expect-send对组成:expect等待输出中输出特定的字符,通常是一个提示符,然后发送特定的响应。例如下面的 

      Chat脚本实现等待标准输出出现Login:字符串,然后发送somebody作为用户名;然后等待Password:提示符,并发出响应 

sillyme。

        引用:Login: somebody Password: sillyme

        这个脚本用来实现一个登录过程,并用特定的用户名和密码实现登录。

        Expect最简单的脚本操作模式本质上和Chat脚本工作模式是一样的。

        例子:

        1、实现功能

        下面我们分析一个响应chsh命令的脚本。我们首先回顾一下这个交互命令的格式。假设我们要为用户chavez改变登录脚本,要求实现的命令交互过程如下:

        引用:# chsh chavez

        Changing the login shell for chavez

        Enter the new value, or press return for the default

        Login Shell [/bin/bash]: /bin/tcsh

        #

        可以看到该命令首先输出若干行提示信息并且提示输入用户新的登录shell。我们必须在提示信息后面输入用户的登录shell或者直接回车不修改登录shell。

        2、下面是一个能用来实现自动执行该命令的Expect脚本:

        #!/usr/bin/expect

        # Change a login shell to tcsh

        set user [lindex $argv 0]

        spawn chsh $user

        expect "]:"

        send "/bin/tcsh "

        expect eof

        exit

        这个简单的脚本可以解释很多Expect程序的特性。和其他脚本一样首行指定用来执行该脚本的命

令程序,这里是/usr/bin/expect。程序第一行用来获得脚本的执行参数(其保存在数组$argv中,从0号开始

是参数),并将其保存到变量user中。


        第二个参数使用Expect的spawn命令来启动脚本和命令的会话,这里启动的是chsh命令,实际上

命令是以衍生子进程的方式来运行的。


        随后的expect和send命令用来实现交互过程。脚本首先等待输出中出现]:字符串,一旦在输出中

出现chsh输出到的特征字符串(一般特征字符串往往是等待输入的最后的提示符的特征信息)。对于其他不匹

配的信息则会完全忽略。当脚本得到特征字符串时,expect将发送/bin/tcsh和 


      一个回车符给chsh命令。最后脚本等待命令退出(chsh结束),一旦接收到标识子进程已经结束的eof字符,expect脚本也就退出结束。

        3、决定如何响应

        管理员往往有这样的需求,希望根据当前的具体情况来以不同的方式对一个命令进行响应。我们可以通过后面的例子看到expect可以实现非常复杂的条件响应,而仅仅通过简单的修改预处理脚本就可以实现。下面的例子是一个更复杂的expect-send例子:

        expect -re "\[(.*)]:"


        if {$expect_out(1,string)!="/bin/tcsh"} {


        send "/bin/tcsh" }


        send " "


        expect eof


        在这个例子中,第一个expect命令现在使用了-re参数,这个参数表示指定的的字符串是一个正

则表达式,而不是一个普通的字符串。对于上面这个例子里是查找一个左方括号字符(其必须进行三次逃逸

(escape),因此有三个符号,因为它对于expect和正则表达时来说都是特殊字符)后面跟有 零个或多个字符,最后是一个右方括号字符。这里.*表示表示一个或多个任意字符,将其存放在()中


是因为将匹配结果存放在一个变量中以实现随后的对匹配结果的访问。


        当发现一个匹配则检查包含在[]中的字符串,查看是否为/bin/tcsh。如果不是则发送/bin/tcsh


给chsh命令作为输入,如果是则仅仅发送一个回车符。这个简单的针对具体情况发出不同相响应的小例子说


明了expect的强大功能。

        在一个正则表达时中,可以在()中包含若干个部分并通过expect_out数组访问它们。各个

部分在表达式中从左到右进行编码,从1开始(0包含有整个匹配输出)。()可能会出现嵌套情况,这这种情况

下编码从最内层到最外层来进行的。

        4、使用超时

        下一个expect例子中将阐述具有超时功能的提示符函数。这个脚本提示用户输入,如果在给定的时间内没有输入,则会超时并返回一个默认的响应。这个脚本接收三个参数:提示符字串,默认响应和超时时间(秒)。

        #!/usr/bin/expect

        # Prompt function with timeout and default.

        set prompt [lindex $argv 0]

        set def [lindex $argv 1]

        set response $def

        set tout [lindex $argv 2]

        脚本的第一部分首先是得到运行参数并将其保存到内部变量中。

        send_tty "$prompt: "

        set timeout $tout

        expect " " {

        set raw $expect_out(buffer)

        # remove final carriage return

        set response [string trimright "$raw" " "]

        }

        if {"$response" == "} {set response $def}

        send "$response

        这是脚本其余的内容。可以看到send_tty命令用来实现在终端上显示提示符字串和一个冒号及空格。set 

      timeout命令设置后面所有的expect命令的等待响应的超时时间为$tout(-l参数用来关闭任何超时设置)。

              

      然后expect命令就等待输出中出现回车字符。如果在超时之前得到回车符,那么set命令就会将用户输入的内容赋值给变脸raw。随后的命令将用户输入内容最后的回车符号去除以后赋值给变量response。 


        然后,如果response中内容为空则将response值置为默认值(如果用户在超时以后没有输入或者用户仅仅输入了回车符)。最后send命令将response变量的值加上回车符发送给标准输出。

        一个有趣的事情是该脚本没有使用spawn命令。 该expect脚本会与任何调用该脚本的进程交互。

        如果该脚本名为prompt,那么它可以用在任何C风格的shell中。

        % set a='prompt "Enter an answer" silence 10'

        Enter an answer: test

        % echo Answer was "$a"

        Answer was test

        prompt设定的超时为10秒。如果超时或者用户仅仅输入了回车符号,echo命令将输出

        Answer was "silence"

        5、一个更复杂的例子

        下面我们将讨论一个更加复杂的expect脚本例子,这个脚本使用了一些更复杂的控制结构和很多复杂的交互过程。这个例子用来实现发送write命令给任意的用户,发送的消息来自于一个文件或者来自于键盘输入。

        #!/usr/bin/expect

        # Write to multiple users from a prepared file

        # or a message input interactively

        if {$argc<2} {

        send_user "usage: $argv0 file user1 user2 ... "

        exit

        }

        send_user命令用来显示使用帮助信息到父进程(一般为用户的shell)的标准输出。

        set nofile 0

        # get filename via the Tcl lindex function

        set file [lindex $argv 0]

        if {$file=="i"} {

        set nofile 1

        } else {

        # make sure message file exists

        if {[file isfile $file]!=1} {

        send_user "$argv0: file $file not found. "

        exit }}

        这部分实现处理脚本启动参数,其必须是一个储存要发送的消息的文件名或表示使用交互输入得到发送消的内容的"i"命令。

        变量file被设置为脚本的第一个参数的值,是通过一个Tcl函数lindex来实现的,该函数从列表/数组得到一个特定的元素。[]用来实现将函数lindex的返回值作为set命令的参数。

        如果脚本的第一个参数是小写的"i",那么变量nofile被设置为1,否则通过调用Tcl的函数isfile来验证参数指定的文件存在,如果不存在就报错退出。

        可以看到这里使用了if命令来实现逻辑判断功能。该命令后面直接跟判断条件,并且执行在判断条件后的{}内的命令。if条件为false时则运行else后的程序块。

        set procs {}

        # start write processes

        for {set i 1} {$i<$argc}

        {incr i} {

        spawn -noecho write

        [lindex $argv $i]

        lappend procs $spawn_id

        }

        最后一部分使用spawn命令来启动write进程实现向用户发送消息。这里使用了for命令来实现循环控制功能,循环变量首先设置为1,然后因 

      此递增。循环体是最后的{}的内容。这里我们是用脚本的第二个和随后的参数来spawn一个write命令,并将每个参数作为发送消息的用户名。 

      lappend命令使用保存每个spawn的进程的进程ID号的内部变量$spawn_id在变量procs中构造了一个进程ID号列表。

        if {$nofile==0} {

        setmesg [open "$file" "r"]

        } else {

        send_user "enter message,

        ending with ^D: " }

        最后脚本根据变量nofile的值实现打开消息文件或者提示用户输入要发送的消息。

        set timeout -1

        while 1 {

        if {$nofile==0} {

        if {[gets $mesg chars] == -1} break

        set line "$chars "

        } else {

        expect_user {

        -re " " {}

        eof break }

        set line $expect_out(buffer) }

        foreach spawn_id $procs {

        send $line }

        sleep 1}

        exit

        上面这段代码说明了实际的消息文本是如何通过无限循环while被发送的。while循环中的 

      if判断消息是如何得到的。在非交互模式下,下一行内容从消息文件中读出,当文件内容结束时while循环也就结束了。(break命令实现终止循环) 。

        在交互模式下,expect_user命令从用户接收消息,当用户输入ctrl+D时结束输入,循环同时结束。 

      两种情况下变量$line都被用来保存下一行消息内容。当是消息文件时,回车会被附加到消息的尾部。

        foreach循环遍历spawn的所有进程,这些进程的ID号都保存在列表变量$procs中,实现分别和各个进程通信。send命令组成了 

      foreach的循环体,发送一行消息到当前的write进程。while循环的最后是一个sleep命令,主要是用于处理非交互模式情况下,以确保消息 

      不会太快的发送给各个write进程。当while循环退出时,expect脚本结束





使用expect实现自动登录的脚本,网上有很多,可是都没有一个明白的说明,初学者一般都是照抄、收藏。可是为什么要这么写却不知其然。本文用一个最短的例子说明脚本的原理。 

  脚本代码如下: 

  ############################################## 

  #!/usr/bin/expect 

  set timeout 30 

  spawn ssh -l username 192.168.1.1 

  expect "password:" 

  send "ispass\r" 

  interact 

  ############################################## 

  1. [#!/usr/bin/expect] 

  这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。 

  注意:这一行需要在脚本的第一行。 

  2. [set timeout 30] 

  基本上认识英文的都知道这是设置超时时间的,现在你只要记住他的计时单位是:秒 

  3. [spawn ssh -l username 192.168.1.1] 

  spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。所以不要用 “which spawn“之类的命令去找spawn命令。好比windows里的dir就是一个内部命令,这个命令由shell自带,你无法找到一个dir.com 或 dir.exe 的可执行文件。 

  它主要的功能是给ssh运行进程加个壳,用来传递交互指令。 

  4. [expect "password:"] 

  这里的expect也是expect的一个内部命令,有点晕吧,expect的shell命令和内部命令是一样的,但不是一个功能,习惯就好了。这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是前面设置的30秒 

  5. [send "ispass\r"] 

  这里就是执行交互动作,与手工输入密码的动作等效。 

  温馨提示: 命令字符串结尾别忘记加上“\r”,如果出现异常等待的状态可以核查一下。 

  6. [interact] 

  执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。如果你只是登录过去执行 

  #!/usr/bin/expect #注意安装的路径,不确定 whereis expect 一下 

  # Change a login shell to bash 

  set user [lindex $argv 0] 

  spawn bash $user 

  expect "]:" 

  send "/bin/bash " 

  expect eof 

  exi





使用expect自动登录

一,什么是expect?
在做系统管理时,我们很多时候需要输入密码,例如:连接 ssh,连接ftp,
那么如何能做到不输入密码吗?
我们需要有一个工具,能代替我们实现与终端的交互,
那么,就是它:expect,管理员的最好的朋友之一 
它能够代替我们实现与终端的交互,我们不必再守候在电脑旁边输入密码,
或是根据系统的输出再运行相应的命令,
这些都可以由expect代替我们来完成

说明:expect到底是什么?
expect是一种脚本语言,使用起来非常简单,我们看后面的例子即可以了解到了

三,安装expect

备注:因为expect是基于tcl的,所以需要你的系统中安装有tcl
如何检查?
[root@dev ~]# whereis tcl
tcl: /usr/lib/tcl8.4 /usr/share/tcl8.4
如果看不到结果,请先安装tcl
安装,
[root@dev ~]# yum install expect
也可以从下载for相应发行版的rpm包

四,使用expect自动登录的例子
1,程序例子的内容 :
先做功能 上的说明
此程序ssh登录到作为参数传递过来的ip地址上
然后执行: df -h
free -m
uptime
来检查系统的情况


[root@dev ~]# cat monitor_auto
#!/usr/bin/expect -f

#-------------------------------------------------- about us
# product: monitorone
# Author: liuhongdi
# Last Modified: 2008-05-13
# version: 0.3.2
# user:this script will help you to monitor many linux(unix) machine
# license: this script is based GPL

#-------------------------------------------------- set the variable,you can modify the value

set loginuser "root" 
set loginpass {passwordonthishost}

set ipaddr [lrange $argv 0 0] 
set timeout 300
set cmd_prompt "]#|~]?"

#-------------------------------------------------- login by ssh 
spawn ssh $loginuser@$ipaddr 
set timeout 300
expect {
-re "Are you sure you want to continue connecting (yes/no)?" {
send "yes\r"
} -re "assword:" {
send "$loginpass\r"
} -re "Permission denied, please try again." {
exit
} -re "Connection refused" {
exit
} timeout {
exit
} eof {
exit
}
}

expect {
-re "assword:" {
send "$loginpass\r"
}
-re $cmd_prompt {
send "\r"
}
}

#---------------------------------------------------- now,we do some commands
exec sleep 1
expect {
-re $cmd_prompt {
send "df -h\r"
}
}

exec sleep 1
expect { 
-re $cmd_prompt { 
send "free -m\r"
}
}

exec sleep 1
expect {
-re $cmd_prompt {
send "uptime\r"
}
}
exec sleep 1


#--------------------------------------------------
expect {
-re $cmd_prompt {
send "exit\r"
}
}


exit
#interact

2,程序 运行的显示结果

[root@dev ~]# ./monitor_auto 209.209.94.107
spawn ssh root@209.209.94.107
root@209.209.94.107's password: 
Last login: Sun Feb 15 01:42:39 2009 from 201.103.105.49

[root@ws ~]# 
[root@ws ~]# df -h
Filesystem ?? ???? ???? ????% ?????
/dev/mapper/VolGroup00-LogVol00
133G 72G 55G 57% /
/dev/sda1 99M 13M 82M 14% /boot
none 1014M 0 1014M 0% /dev/shm
209.209.94.109:/www/pics
5.9T 5.6T 138G 98% /bank/bank1
[root@ws ~]# free -m
total used free shared buffers cached
Mem: 2026 1955 71 0 72 1621
-/+ buffers/cache: 261 1764
Swap: 1983 68 1915
[root@ws ~]# uptime
01:48:00 up 561 days, 8:53, 2 users, load average: 0.13, 0.09, 0.07
[root@ws ~]# [root@dev ~]# 


四,对此程序的详细说明:
1,set loginuser "root" 
set用来定义变量,定义之后的代码中可以使用所定义的变量
使用时注意需添加$符号
使用时的例子: spawn ssh $loginuser@$ipaddr  





1. expect 是基于tcl 演变而来的,所以很多语法和tcl 类似,基本的语法如下

所示:

1.1 首行加上/usr/bin/expect

1.2 spawn: 后面加上需要执行的shell 命令,比如说spawn sudo touch testfile

1.3 expect: 只有spawn 执行的命令结果才会被expect 捕捉到,因为spawn 会启

动一个进程,只有这个进程的相关信息才会被捕捉到,主要包括:标准输入的提

示信息,eof 和timeout。

1.4 send 和send_user:send 会将expect 脚本中需要的信息发送给spawn 启动

的那个进程,而send_user 只是回显用户发出的信息,类似于shell 中的echo 而

已。


2. 一个小例子,用于linux 下账户的建立:

filename: account.sh,可以使用./account.sh newaccout 来执行;

1 #!/usr/bin/expect

2

3 set passwd "mypasswd"

4 set timeout 60

5

6 if {$argc != 1} {

7 send "usage ./account.sh \$newaccount\n"

8 exit

9 }

10

11 set user [lindex $argv [expr $argc-1]]

12

13 spawn sudo useradd -s /bin/bash -g mygroup -m $user

14

15 expect {

16 "assword" {

17 send_user "sudo now\n"

18 send "$passwd\n"

19 exp_continue

20 }

21 eof

22 {

23 send_user "eof\n"

24 }

25 }

26

27 spawn sudo passwd $user

28 expect {

29 "assword" {

30 send "$passwd\n"

31 exp_continue

32 }

33 eof

34 {

35 send_user "eof"

36 }

37 }

38

39 spawn sudo smbpasswd -a $user

40 expect {

41 "assword" {

42 send "$passwd\n"

43 exp_continue

44 }

45 eof

46 {

47 send_user "eof"

48 }

49 }


3. 注意点:


第3 行: 对变量赋值的方法

第4 行: 默认情况下,timeout 是10 秒;

第6 行: 参数的数目可以用$argc 得到;

第11 行:参数存在$argv 当中,比如取第一个参数就是[lindex $argv 0];并且

如果需要计算的话必须用expr,如计算2-1,则必须用[expr 2-1]

第13 行:用spawn 来执行一条shell 命令,shell 命令根据具体情况可自行调整;

有文章说sudo 要加-S,经过实际测试,无需加-S 亦可;

第15 行:一般情况下,如果连续做两个expect,那么实际上是串行执行的,用。expect 与“{ ”之间直接必须有空格或则TAB间隔,否则会出麻烦,会报错invalid command name "expect{" 

例子中的结构则是并行执行的,主要是看匹配到了哪一个;在这个例子中,如果

你写成串行的话,即

expect "assword"

send "$passwd\n"

expect eof

send_user "eof"

那么第一次将会正确运行,因为第一次sudo 时需要密码;但是第二次运行时由于

密码已经输过(默认情况下sudo 密码再次输入时间为5 分钟),则不会提示用户

去输入,所以第一个expect 将无法匹配到assword,而且必须注意的是如果是

spawn 命令出现交互式提问的但是expect 匹配不上的话,那么程序会按照timeout

的设置进行等待;可是如果spawn 直接发出了eof 也就是本例的情况,那么expect

"assword"将不会等待,而直接去执行expect eof。

这时就会报expect: spawn id exp6 not open,因为没有spawn 在执行,后面的

expect 脚本也将会因为这个原因而不再执行;所以对于类似sudo 这种命令分支

不定的情况,最好是使用并行的方式进行处理;

第17 行:仅仅是一个用户提示而已,可以删除;

第18 行:向spawn 进程发送password;

第19 行:使得spawn 进程在匹配到一个后再去匹配接下来的交互提示;

第21 行:eof 是必须去匹配的,在spawn 进程结束后会向expect 发送eof;如果

不去匹配,有时也能运行,比如sleep 多少秒后再去spawn 下一个命令,但是不

要依赖这种行为,很有可能今天还可以,明天就不能用了;


4. 其他

下面这个例子比较特殊,在整个过程中就不能expect eof 了:

1 #!/usr/bin/expect

2

3 set timeout 30

4 spawn ssh 10.192.224.224

5 expect "password:"

6 send "mypassword\n"

7 expect "*$"

send "mkdir tmpdir\n" #远程执行命令用send发送,不用spawn

9 expect "*$" #注意这个地方,要与操作系统上环境变量PS1相匹配,尤其是有PS1有空格的情况下,一定在expct "*$ "把空格加上,加不上你就完蛋了。我试过。

这个例子实际上是通过ssh 去登录远程机器,并且在远程机器上创佳一个目录,

我们看到在我们输入密码后并没有去expect eof,这是因为ssh 这个spawn 并没

有结束,而且手动操作时ssh 实际上也不会自己结束除非你exit;所以你只能

expect bash 的提示符,当然也可以是机器名等,这样才可以在远程创建一个目

录。

注意,请不要用spawn mkdir tmpdir,这样会使得上一个spawn 即ssh 结束,那

么你的tmpdir 将在本机建立。

当然实际情况下可能会要你确认ssh key,可以通过并行的expect 进行处理,不

多赘述。


5. 觉得bash 很多情况下已经很强大,所以可能用expect 只需要掌握这些就好了,

其他的如果用到可以再去google 了。


源代码图片:

6 \实例:下面这个脚本是完成对单个服务器scp任务。

 1: #!/usr/bin/expect
 2: 
 3: set timeout 10
 4: set host [lindex $argv 0]
 5: set username [lindex $argv 1]
 6: set password [lindex $argv 2]
 7: set src_file [lindex $argv 3]
 8: set dest_file [lindex $argv 4]
 9: 
10: spawn scp  $src_file $username@$host:$dest_file
 11: expect {
 12:     "(yes/no)?"
 13:         {
 14:             send "yes\n"
 15:             expect "*assword:" { send "$password\n"}
 16:         }
 17:     "*assword:"
 18:         {
 19:             send "$password\n"
 20:         }
 21:     }
 22: expect "100%"
 23: expect eof
参考源代码图片:

注意代码刚开始的第一行,指定了expect的路径,与shell脚本相同,这一句指定了程序在执行时到哪里去寻找相应的启动程序。代码刚开始还设定了timeout的时间为10秒,如果在执行scp任务时遇到了代码中没有指定的异常,则在等待10秒后该脚本的执行会自动终止。

spawn代表在本地终端执行的语句,在该语句开始执行后,expect开始捕获终端的输出信息,然后做出对应的操作。expect代码中的捕获的(yes/no)内容用于完成第一次访问目标主机时保存密钥的操作。有了这一句,scp的任务减少了中断的情况。代码结尾的expect eof与spawn对应,表示捕获终端输出信息的终止。

 

有了这段expect的代码,还只能完成对单个远程主机的scp任务。如果需要实现批量scp的任务,则需要再写一个shell脚本来调用这个expect脚本。

1: #!/bin/sh

 2: 
 3: list_file=$1
 4: src_file=$2
 5: dest_file=$3
 6: 
7: cat $list_file | while    read line
 8: do
 9:     host_ip=`echo $line | awk '{print $1}'`
 10:     username=`echo $line | awk '{print $2}'`
 11:     password=`echo $line | awk '{print $3}'`
 12:     echo "$host_ip"
 13:     ./expect_scp $host_ip $username $password $src_file $dest_file
 15: done

参考代码图片如下:

很简单的代码,指定了3个参数:列表文件的位置、本地源文件路径、远程主机目标文件路径。需要说明的是其中的列表文件指定了远程主机ip、用户名、密码,这些信息需要写成以下的格式:

IP username password

中间用空格或tab键来分隔,多台主机的信息需要写多行内容。

这样就指定了两台远程主机的信息。注意,如果远程主机密码中有“$”、“#”这类特殊字符的话,在编写列表文件时就需要在这些特殊字符前加上转义字符,否则expect在执行时会输入错误的密码。


阅读(1338) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~