Expect within bash script

2019-07-15 08:28发布

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! :)

2条回答
▲ chillily
2楼-- · 2019-07-15 08:41

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
'
查看更多
不美不萌又怎样
3楼-- · 2019-07-15 08:55

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)

查看更多
登录 后发表回答