-1

I'm trying to write a bash script to reboot multiple machines via ssh that are all password protected. I have all the IPs listed in a .txt file and want the script to read the IPs from there. I've been messing with the expect command since my mac does not have sshpass. Is there a way to do this without sshpass??

I have this so far:

#!/bin/bash

for server in 'testreboot.txt'; do
expect -c 'spawn ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 
administrator@$server "sudo shutdown -r now"; expect "Password:"; send 
"password\r"; interact'
done

In testreboot.txt I simply have the IP address listed of a test machine. Is that ok or do I need to assign it to a variable? I keep getting a variable error when I try to run it.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
Danny
  • 11

1 Answers1

2

You have single quoted the string; this prevents the shell from interpolating $server. TCL (which is what expect code is written in) also uses the $server form to interpolate variables, but you have not set server ... anywhere in your TCL code. Hence the error, as the shell did not interpolate it nor did the TCL set it. One method would be to double quote the TCL expression which will allow the shell to interpolate in the shell $server variable:

$ server=example; expect -c 'puts $server'
can't read "server": no such variable
    while executing
"puts $server"
$ server=example; expect -c "puts $server"
example
$ 

However this will mean that any " in the TCL code will need to be escaped to protect them from messing with the shell interpolation which will probably get ugly real fast and will be hard to debug, especially as the commands get longer and more complicated.

$ server=example; expect -c "puts \"a server named '$server'\""
a server named 'example'
$ 

Another option would be to read the argument into a TCL variable, but, alas, the -c flag code of expect has no access to the arguments list in char *argv[] as the -c code is run before the arguments list is made available for use by TCL. Therefore to use $server as a TCL variable the script would need to be rewritten in TCL:

#!/usr/bin/env expect

set fh [open testreboot.txt r]

while {[gets $fh server] >= 0} {
    spawn -noecho ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 \
       administrator@$server
    expect -ex "Password:"
    send "Hunter2\r"
    expect -ex {$ }
    send "sudo shutdown -r now\r"
    expect -ex "Password:"
    send "Hunter2\r"
    interact
}

which will may need improvements for error handling, timeouts, matching the shell prompt better, etc.

thrig
  • 34,938