1

I have an expect script that will login to the remote server and execute a python script. In python script I have set sys.exit(1) for a certain condition so that it would stop execution when that condition is met. Is there way to know if python script stopped execution or ran fine?
(or) is there a way to read the output that python script produces (that is I would like to read output of send "python pythonscript.py arg1\r"). Any approach is fine. Please suggest ideas

expectscript.exp

#!/usr/bin/expect

eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no user@******
expect "Password:"
send "password\r"
expect "$username$"
set prompt ":|#|\\\$"
set timeout -1
send "cd /Users/username/Documents/folder/\r"
send "python pythonscript.py arg1\r"
expect $prompt
Ram
  • 65
  • 4
  • 12
  • I think you can find what you're looking for here: https://stackoverflow.com/questions/23614039/how-to-get-the-exit-code-of-spawned-process-in-expect-shell-script – Alessandro Gaballo Sep 17 '19 at 14:52

2 Answers2

1

Run as command

spawn ssh -c "python pythonscript.py arg1"
expect $prompt

Try to use spawn -c for executable commands as this will fetch the result back, sending them terminates after execution.

Avinash Yadav
  • 781
  • 7
  • 13
1

This is where you need to expect -re to capture the output before the prompt:

send "cd /Users/username/Documents/folder/\r"
expect $prompt
send "python pythonscript.py arg1\r"
expect -re "(.+)$prompt"
set pythonOutput $expect_out(1,string)

expect buffers output in the expect_out array, and the array key 1,string (note, no space there) contains the contents of the first capturing parentheses of the regex pattern.

Also note, the output will include the python command, and lines are ended with \r\n: so you can do something like:

set outputLines [lrange [lmap line [split $pythonOutput \n] {regsub {\r$} $line ""] 1 end]
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • Isn't there a race condition?! I.e couldn't `expect -re "(.+)$prompt"` potentially be executed after some output has already been produced, hence being futile? – Unknown Jul 08 '23 at 12:22
  • I don't understand your comment. Can you think of an example where this would fail? – glenn jackman Jul 08 '23 at 12:52
  • Python is slow to execute, but if it was a faster-to-respond interaction, couldn't that send command produce output before `expect -re` gets to run? (The reason I'm asking, is because I'm working with a 100% deterministic script that sometimes produces results and sometimes it doesn't, and I believe only such a race condition could be to blame.) I think, ideally, Expect should've had a send-and-listen command to cover such cases atomically. – Unknown Jul 08 '23 at 13:09
  • 1
    `send` does not produce any output: the spawned process does. The output is buffered. The expect command watches the buffer until a match is found. It's OK that output is produced before the expect command executes. – glenn jackman Jul 08 '23 at 13:13
  • Given your god-level status, I've to take your word for it. But there remains some doubt in me on potential race conditions. I'd be happy to paste the code here if you don't mind. – Unknown Jul 08 '23 at 13:32
  • I finally figured it out. Put a `sleep 0.5` before `expect -re` and my script works w/o a hiccup now. Seems like `expect -re` was actually getting executed too early, rather than late. – Unknown Jul 08 '23 at 18:25
  • 1
    Generally, if you need to sleep your patterns are not precise enough. Run with `expect -d` and check the verbose debugging to see when your patterns match when you don't want them to. – glenn jackman Jul 09 '23 at 02:29
  • This msg: `does "\r\n" (spawn_id exp7) match regular expression "(.+)\n"? Gate "*\n"? gate=yes re=yes` is what I get from a `expect -re "(.+)\n"` if not done with a brief sleep in advance. Sleep solves it however. I could make the regex fancier, but why bother. – Unknown Jul 09 '23 at 21:59
  • That pattern is really so vague as to be almost useless: match any line of text. – glenn jackman Jul 10 '23 at 14:27
  • I don't see your pattern being all that much more exclusive either. To give you context, it's to extract the result of an openssl decryption of a file. You enter the pass (via send in this script), and soon after, openssl prints the result on the next line. You `expect -re` too soon, and you get nothing. Wait half a sec instead, and voila! – Unknown Jul 10 '23 at 17:42
  • 1
    Assuming the openssl command ends after it emits the decrypted text, then after sending the password `expect eof`, and then parse `$expect_out(buffer)` in the same fashion I show above. – glenn jackman Jul 10 '23 at 17:51
  • That was the trick! Thank you, god! :) – Unknown Jul 10 '23 at 18:07