3

I am trying to implement an expect script into a bash script. Bear with me since I am fairly new to bash/expect.

Here is the expect script that works as intended:

log_user 0

file delete foo.txt

set fh [open foo.txt a]

set servers {xxx@server1 xxx@server2}

foreach s $servers {
spawn ssh $s
expect "password: "
send "PASSWORD\r"
expect "$ "
send "grep "something" /some/log/file.log"
expect "$ " { puts $fh "$expect_out(buffer)"}
send "exit\r"
}

close $fh

Now, I am hoping to include this expect script in a bash script but it is not working as intended.

Here is what I have so far:

#!/bin/bash

XYZ=$(expect -c "
file delete foo.txt

set fh [open foo.txt a]

set servers {xxx@server1 xxx@server2}

foreach s $servers {
spawn ssh $s
expect "password: "
send "PASSWORD\r"
expect "$ "
send "grep "something" /some/log/file.log"
expect "$ " { puts $fh "$expect_out(buffer)"}
send "exit\r"
}

close $fh
")

echo "$XYZ"

The error I am getting is:

command substitution: line 42: syntax error near unexpected token `('
command substitution: line 42: `expect "$ " { puts $fh "$expect_out(buffer)"}'

I'm open to any other ways to implement this! :)

1
  • In your original script, the variable $servers is expanded by Tcl, since the whole stuff is a Tcl program. In your second script, the variable $server is expanded by bash, and since there is no bash variable with this name, it is replaced by the null string. Commented Feb 21, 2017 at 7:11

2 Answers 2

5

You can use /usr/bin/expect -c to execute expect commands :

#!/bin/bash

/usr/bin/expect -c ' 

file delete foo.txt

set fh [open foo.txt a]

set servers {xxx@server1 xxx@server2}

foreach s $servers {
spawn ssh $s
expect "password: "
send "PASSWORD\r"
expect "$ "
send "grep "something" /some/log/file.log"
expect "$ " { puts $fh "$expect_out(buffer)"}
send "exit\r"
}

close $fh
'
Sign up to request clarification or add additional context in comments.

2 Comments

Excellent, this is exactly what I was looking for. Thanks!
Is there a way to pass variables to the expect code using this approach?
1

Bertrand's answer is one way to solve your question, but does not explain the problem with what you were doing.

Bash attempts to expand variables inside double quoted strings, so your expect script will see blank spaces where you want to see $servers, $s, and $fh. Further, you have triply-nested sets of double-quoted strings going on that will cause all sorts of problems with parsing the arguments to expect.

It's a matter of opinion, but I think when something gets to a certain point where it's considered a program of its own, it should be separated into a separate file.

#!/usr/bin/expect
log_user 0

file delete foo.txt

set fh [open foo.txt a]

set servers {xxx@server1 xxx@server2}

foreach s $servers {
    spawn ssh $s
    expect "password: "
    send "PASSWORD\r"
    expect "$ "
    send "grep 'something' /some/log/file.log"
    expect "$ " {
        puts $fh "$expect_out(buffer)"
    }
    send "exit\r"
}

close $fh

Make sure it's executable, and then call it from your bash script:

#!/bin/bash
/usr/local/bin/my_expect_script

(To do this really properly, you should set up public key authentication and then you can get rid of expect altogether by running ssh server "grep 'something' /some/log/file.log" directly from bash)

1 Comment

Also, the logging going on in your expect script could be done much more concisely on the bash side of things.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.