2017-01-25 6 views
2

Я пытаюсь нажимать один набор команд на несколько удаленных хостов. Я могу использовать следующее на индивидуальной основе:
ssh [email protected] "bash -s" <./commands.sh
Я могу поместить это в цикл, но затем я застрял в наборе пароля n раз. Отключение подсказок пароля в конфигурационных файлах SSH не является для меня вариантом. Я попытался использовать ожидание в цикле, но я не могу заставить его работать.Невозможно выполнить SSH скрипт команд bash через expect

#!/bin/bash 
HOSTS="host1 host2" 
read -sp "Password: " PASSWORD 
for HOST in $HOSTS; do 
    expect -c " 
    spawn /usr/bin/ssh [email protected]$HOST "bash -s" <./commands.sh 
    expect_before { 
     "*yes/no*" {send "yes"\r;exp_continue}} 
    expect { 
     "*Password*" {send $PASSWORD\r;interact}} 
    exit" 
done 

Я получаю следующее сообщение об ошибке:

spawn /usr/bin/ssh [email protected] bash 
expect: invalid option -- 's' 
usage: expect [-div] [-c cmds] [[-f] cmdfile] [args] 
spawn /usr/bin/ssh [email protected] bash 
expect: invalid option -- 's' 
usage: expect [-div] [-c cmds] [[-f] cmdfile] [args] 

Любые идеи? Похоже, что ожидание пытается интерпретировать команды bash. Я не знаю, как остановить это.

+2

Первый '' '' '' bash -s ''слишком рано заканчивает ваш скрипт' ожидать'. Измените '' '' '' '' на протяжении всего сценария ожидания (от строки 'spawn' до' exit ' строка – cxw

+1

«... не вариант». Было ли сказано, что требуется аутентификация пароля или вы просто не знаете, как использовать аутентификацию с открытым ключом? – chepner

+1

Я изменил свою строку кода, содержащую команду ssh, на следующую и все сработало. 'spawn sh -c {ssh root @ $ HOST 'bash -ls' Mike

ответ

1

Решение:
заменить
spawn /usr/bin/ssh [email protected]$HOST "bash -s" <./commands.sh
с
spawn sh -c {ssh [email protected]$HOST 'bash -ls' < /tmp/commands.sh}
Финальный код:

#!/bin/bash 

HOSTS="host1 host2" 

read -sp "Password: " PASSWORD 

for HOST in $HOSTS; do 
     expect -c " 
       spawn sh -c {ssh [email protected]$HOST 'bash -ls' < /tmp/commands.sh} 
       expect_before { 
       "*yes/no*" {send "yes"\r;exp_continue}} 
       expect { 
       "*assword*" {send $PASSWORD\r;interact}} 
       exit" 
done 
0

Я хотел бы предложить следующее:

#!/bin/bash 
hosts=(host1 host2) 
read -sp "Password: " password 
for host in "${hosts[@]}"; do 
    env h="$host" p="$password" expect <<'END_EXPECT' 
     spawn sh -c "/usr/bin/ssh [email protected]$env(h) 'bash -s' <./commands.sh" 
     expect { 
      "*yes/no*" {send "yes\r"; exp_continue} 
      "*Password*" {send "$env(p)\r"} 
     } 
     interact 
END_EXPECT 
done 

заметки

  • использует имена переменных в нижнем регистре: оставить верхний регистр имён переменным для командного интерпретатора
  • использует цитируемый Heredoc, чтобы содержать ожидать код
    • , что позволяет использовать одинарные и двойные кавычки внутри ожидать, не беспокоясь о цитировании ад в оболочке
  • использует env передавать переменные оболочки ожидать через окружающую среду
  • упрощает ожидать statem ЛОР

Опасность с использованием

expect -c " ...; expect "*Password*" ..." 

является то, что внутренние двойные кавычки получить соответствие с внешними кавычки, и удаляются оболочкой. Это оставляет *Password* как голый шар, который оболочка может расширять на основе файлов в вашем текущем каталоге и настройках оболочки. Например, создайте файл с именем «Пароль» (с пробелом), и вы получите ошибку .

+0

Это не работает для меня. Это не вызывает никаких ошибок, но кажется, что он неправильно подключается к моим хостам. Я пробовал несколько небольших настроек без каких-либо успехов. – Mike

+0

запустите его с 'expect -d', чтобы увидеть вывод отладки, чтобы убедиться, что переменные передаются правильно. –

+0

Я сравнивал вывод нашего кода с отладкой, как вы и предполагали. Ваш код отправляет пароль на spawn_id exp4, но затем получает eof из spawn_id exp0. Мой код получает оба этих сообщения из spawn_id exp4. Я думаю, что это и вызывает проблему. – Mike