"expect" 的基本练习 - 初学者

Basic exercise on "expect" - beginner

我是初学者学习该工具"expect",现阶段我正在尝试几个练习。

下面是一个简单的练习,说明了两个连续的"spawn"命令的使用——更改unix系统的密码,然后恢复旧的。基本上,将手动操作自动化:

$passwd
Changing password for <username>.
(current) UNIX password: 
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully

问题是 "expect" 神秘地停在第二个生成点的入口处等待提示.. 让我陷入无尽的谜团中。

#!/usr/bin/expect -f

#PREAMBLE
set timeout -1
set force_conservative 1
set send_slow {1 .1}
if {$force_conservative} {
    set send_slow {1 .1}
    proc send {ignore arg} {
        sleep .1
        exp_send -s -- $arg
    }
}

#ACTUAL CODE
spawn passwd

expect "(current)"
send -- "PW-OLD\r"

expect "Enter"
send -- "PW-NEW\r"

expect "Retype"
send -- "PW-NEW\r"

sleep 1

spawn passwd

expect "(current)"
send -- "PW-NEW"

expect "Enter"
send -- "PW-OLD\r"

expect "Retype"
send -- "PW-OLD\r"
interact

我也很想听听您注意到的任何不好的做法,以及您可能想说的任何好的做法。

下面是 expect -d 的输出(替换第一行 shebang 中的 expect -f),在用户@pynexj 的建议之后。这看起来像是我不知道的实际编码器的调试实用程序。

$./exercise1.sh
expect version 5.45
argv[0] = /usr/bin/expect  argv[1] = -d  argv[2] = ./exercise1.sh  
set argc 0
set argv0 "./exercise1.sh"
set argv ""
executing commands from command file ./exercise1.sh
spawn passwd
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {7848}

expect: does "" (spawn_id exp4) match glob pattern "(current)"? no
Changing password for <username>.
(current) UNIX password: 
expect: does "Changing password for <username>.\r\n(current) UNIX password: " (spawn_id exp4) match glob pattern "(current)"? yes
expect: set expect_out(0,string) "(current)"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "Changing password for <username>.\r\n(current)"
send: sending "PW-OLD\r" to { exp4 }

expect: does " UNIX password: " (spawn_id exp4) match glob pattern "Enter"? no


expect: does " UNIX password: \r\n" (spawn_id exp4) match glob pattern "Enter"? no
Enter new UNIX password: 
expect: does " UNIX password: \r\nEnter new UNIX password: " (spawn_id exp4) match glob pattern "Enter"? yes
expect: set expect_out(0,string) "Enter"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) " UNIX password: \r\nEnter"
send: sending "PW-NEW\r" to { exp4 }

expect: does " new UNIX password: " (spawn_id exp4) match glob pattern "Retype"? no


expect: does " new UNIX password: \r\n" (spawn_id exp4) match glob pattern "Retype"? no
Retype new UNIX password: 
expect: does " new UNIX password: \r\nRetype new UNIX password: " (spawn_id exp4) match glob pattern "Retype"? yes
expect: set expect_out(0,string) "Retype"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) " new UNIX password: \r\nRetype"
send: sending "PW-NEW\r" to { exp4 }
spawn passwd
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {7861}

expect: does "" (spawn_id exp7) match glob pattern "(current)"? no
Changing password for <username>.
(current) UNIX password: 
expect: does "Changing password for <username>.\r\n(current) UNIX password: " (spawn_id exp7) match glob pattern "(current)"? yes
expect: set expect_out(0,string) "(current)"
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) "Changing password for <username>.\r\n(current)"
send: sending "PW-NEW" to { exp7 }

expect: does " UNIX password: " (spawn_id exp7) match glob pattern "Enter"? no
^Csighandler: handling signal(2)
async event handler: Tcl_Eval(exit 130)

我会使用适用于所有密码提示的正则表达式模式:

expect -re "password: $"

sleep 1interact 都更改为 expect eof

# create new password
spawn passwd
expect -re "password: $"; send -- "PW-OLD\r"
expect -re "password: $"; send -- "PW-NEW\r"
expect -re "password: $"; send -- "PW-NEW\r"
expect eof

# restore old password
spawn passwd
expect -re "password: $"; send -- "PW-NEW\r"
expect -re "password: $"; send -- "PW-OLD\r"
expect -re "password: $"; send -- "PW-OLD\r"
expect eof

对于 glob 模式,如果不指定任何通配符,基本上就是在进行字符串相等性检查。你可以这样做:

expect "*(current) UNIX password: "
expect "*Enter new UNIX password: "
expect "*Retype new UNIX password: "

注意密码提示中出现的尾随空格。