Reputation: 573
I have a script that logs into a server and executes a few commands. I need to be able to retrieve the return code from each of those commands in order to determine if the script was successful or not. I wrote the following script which is not doing as I desired. The goal was to execute "cd /I/dont/exist" which would produce error code "1". Use regex to grab the result and set the variable called "result" to that value. Use "result" to determine pass or fail of cd command and exit if it failed.
Currently it will execute all the required steps, but the regex fails to pick up the return code and instead reports that all is well. Based on using "exp_internal 1", it looks like it scans through expect_out and finds a "0" before it finds the "1" it should.
What have I missed here?
script:
spawn bash
expect "$ "
send "cd /I/dont/exist\r"
#clear expect buffer
sleep 1
expect *
sleep 1
#get return code and validate it
send "echo \$?\r"
expect -re "(\\d+)" {
set result $expect_out(1,string)
}
if { $result != 0 } {
puts "Got result $result which is not 0"
exit $result
} else {
puts "didn't have a problem, $result is 0"
}
expect "$ "
Current output:
user@mycomputer:dir/scripts$ expect expect_script.exp
spawn bash
user@mycomputer:dir/scripts$ cd /I/dont/exist
bash: cd: /I/dont/exist: No such file or directory
user@mycomputer:dir/scripts$ echo $?
1
didn't have a problem, 0 is 0
user@mycomputer:dir/scripts$
Expected output:
user@mycomputer:dir/scripts$ expect expect_script.exp
spawn bash
user@mycomputer:dir/scripts$ cd /I/dont/exist
bash: cd: /I/dont/exist: No such file or directory
user@mycomputer:dir/scripts$ echo $?
1
Got result 1 which is not 0
user@mycomputer:dir/scripts$
Output with exp_internal 1:
user@mycomputer:/dir/scripts$ expect expect_script.exp
spawn bash
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {20801}
expect: does "" (spawn_id exp4) match glob pattern "$ "? no
user@mycomputer:/dir/scripts$
expect: does "\u001b]0;user@mycomputer: /dir/scripts\u0007\u001b[01;32muser@mycomputer\u001b[00m:\u001b[01;34m/dir/scripts\u001b[00m$ " (spawn_id exp4) match glob pattern "$ "? yes
expect: set expect_out(0,string) "$ "
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "\u001b]0;user@mycomputer: /dir/scripts\u0007\u001b[01;32muser@mycomputer\u001b[00m:\u001b[01;34m/dir/scripts\u001b[00m$ "
send: sending "cd /I/dont/exist\r" to { exp4 }
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "echo $?\r" to { exp4 }
Gate keeper glob pattern for '(\d+)' is ''. Not usable, disabling the performance booster.
expect: does "" (spawn_id exp4) match regular expression "(\d+)"? (No Gate, RE only) gate=yes re=no
cd /I/dont/exist
bash: cd: /I/dont/exist: No such file or directory
user@mycomputer:/dir/scripts$ echo $?
1
expect: does "cd /I/dont/exist\r\nbash: cd: /I/dont/exist: No such file or directory\r\n\u001b]0;user@mycomputer: /dir/scripts\u0007\u001b[01;32muser@mycomputer\u001b[00m:\u001b[01;34m/dir/scripts\u001b[00m$ echo $?\r\n1\r\n" (spawn_id exp4) match regular expression "(\d+)"? (No Gate, RE only) gate=yes re=yes
expect: set expect_out(0,string) "0"
expect: set expect_out(1,string) "0"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "cd /I/dont/exist\r\nbash: cd: /I/dont/exist: No such file or directory\r\n\u001b]0"
didn't have a problem, 0 is 0
expect: does ";user@mycomputer: /dir/scripts\u0007\u001b[01;32muser@mycomputer\u001b[00m:\u001b[01;34m/dir/scripts\u001b[00m$ echo $?\r\n1\r\n" (spawn_id exp4) match glob pattern "$ "? yes
expect: set expect_out(0,string) "$ "
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ";user@mycomputer: /dir/scripts\u0007\u001b[01;32muser@mycomputer\u001b[00m:\u001b[01;34m/dir/scripts\u001b[00m$ "
Upvotes: 1
Views: 530
Reputation: 247210
Look closely at this:
expect: does "cd /I/dont/exist\r\nbash: cd: /I/dont/exist: No such file or directory\r\n\u001b]0;user@mycomputer: /dir/scripts\u0007\u001b[01;32muser@mycomputer\u001b[00m:\u001b[01;34m/dir/scripts\u001b[00m$ echo $?\r\n1\r\n" (spawn_id exp4) match regular expression "(\d+)"? (No Gate, RE only) gate=yes re=yes
Your prompt has colour codes in it, so the 0
is being found from the prompt itself:
"\u001b]0;user@mycomputer: /dir/scripts\u0007\u001b[01;32muser@mycomputer\u001b[00m:\u001b[01;34m/dir/scripts\u001b[00m$ "
........^
You want to match digits that appear on their own line:
expect -re {\r\n(\d+)\r\n} {set result $expect_out(1,string)}
Also, expect *
is matching the empty string. You want to match your prompt after you send the cd
command.
Upvotes: 1