Используйте Expect в скрипте Bash, чтобы предоставить пароль для команды SSH.

131

Я пытаюсь использовать Expect в сценарии Bash, чтобы предоставить пароль SSH. Предоставление пароля работает, но я не попадаю в сеанс SSH, как должен. Он идет прямо к Башу.

Мой сценарий:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com'
expect "password"
send "$PWD\n"
EOD
echo "you're out"

Результат моего скрипта:

spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
usr@$myhost.example.com's password: you're out

Я хотел бы иметь сеанс SSH и, только когда я выйду из него, вернуться к моему сценарию Bash.

Причина, по которой я использую Bash перед Expect, заключается в том, что мне нужно использовать меню. Я могу выбрать, к какому устройству / устройству подключиться.

Тем, кто хочет ответить, что я должен использовать ключи SSH, воздержитесь.

Максимум
источник
49
пожалуйста, смотрите первую строку: Тем, кто хочет ответить, что я должен использовать SSH-ключи, воздержитесь, пожалуйста
Макс,
54
Я бы отредактировал вашу первую строку, чтобы она была немного дружелюбнее. Вы можете подумать о чем-то вроде «Из-за ограничений я просто не могу использовать ключи SSH, я должен найти способ заставить его работать с ожиданием». Вы должны ожидать, что людям может быть естественно любопытно, почему вы не используете ключи, а просто пытаетесь помочь :) @Ignacio не предлагал вам их использовать, он просто подтвердил это как ограничение, а не надзор.
Тим Пост
В этом случае я бы попробовал использовать кермит. У него очень надежный язык сценариев columbia.edu/kermit/skermit.html#scripts
f3xy

Ответы:

86

Смешивание Bash и Expect - не лучший способ добиться желаемого эффекта. Я бы попробовал использовать только Expect:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com

# Use the correct prompt
set prompt ":|#|\\\$"
interact -o -nobuffer -re $prompt return
send "my_password\r"
interact -o -nobuffer -re $prompt return
send "my_command1\r"
interact -o -nobuffer -re $prompt return
send "my_command2\r"
interact

Пример решения для bash может быть:

#!/bin/bash
/usr/bin/expect -c 'expect "\n" { eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com; interact }'

Это подождет, Enterа затем вернется (на мгновение) к интерактивному сеансу.

Петр Крол
источник
1
отлично работает, спасибо. Что делать, если я хочу ввести команду после входа в систему через SSH, что мне нужно сделать?
Макс
Этот скрипт должен вернуть неработающую оболочку с авторизованным пользователем. Я не понимаю вопроса. Если вы абсолютно хотите использовать тот же сценарий в bash, посмотрите отредактированную запись.
Piotr Król
Так же, как я отправляю пароль при появлении запроса, я хотел бы отправлять системные команды после входа в систему.
Макс
Образец кода был добавлен в сообщение выше. Конечно, это будет работать до тех пор, пока my_commandX не изменит возвращаемое приглашение, если это произойдет, следует изменить переменную приглашения.
Piotr Król
@pietrushnic, не могли бы вы немного объяснить, почему используется "interact -o -nobuffer -re $ prompt return" вместо "expect $ prompt"? последний выглядит более часто используемым ..
Ричард
53

Самый простой способ - использовать sshpass . Это доступно в репозиториях Ubuntu / Debian, и вам не нужно иметь дело с интеграцией expect с Bash.

Пример:

sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh user@192.168.1.200 ls -l /tmp

Приведенную выше команду можно легко интегрировать со сценарием Bash.

Примечание: Пожалуйста , прочитайте соображения безопасности раздел man sshpassдля полного понимания последствий безопасности.

dotnix
источник
Не знаю, хорошее ли это решение, но оно, безусловно, сильно упрощает. Спасибо
erikbwork
9
Очень опасно с точки зрения безопасности - аргументы командной строки могут быть прочитаны любым другим процессом в системе. Их можно перезаписать, и мы надеемся sshpass, что это произойдет, но даже тогда есть период, когда он все еще запускается, прежде чем он сможет это сделать, когда пароль доступен для любого / каждого процесса.
Чарльз Даффи
1
@CharlesDuffy Конечно, вы правы. sshpassиспользуется в сценарии, когда у вас есть простые тестовые сценарии, которые выполняются в локальной сетевой среде, где безопасность не является главной проблемой. Фактически, есть раздел, в man sshpassкотором объясняется целый раздел, посвященный соображениям безопасности. Добавил это в ответ, спасибо.
dotnix
@ erikb85 Обычно пакет делает всю грязную работу за вас, но во всех случаях эти сценарии создаются только для этого использования, тогда это будет ЛУЧШЕ, чем добавление ваших собственных вещей. Этот комментарий о том, чтобы не изобретать велосипед. Работайте с тяжелыми вещами только в том случае, если с ними еще никто не работал. sshpass это хорошая функция.
m3nda 05
2
Для полноты я упоминаю, что «man sshpass» предоставляет подходящие предупреждения системы безопасности потенциальному пользователю, указывает, что «-p» является наименее безопасным способом его использования, и предлагает параметр «-e» для получения пароля через переменную среды. , что, по крайней мере, сохраняет его вне командной строки.
Рон Бурк,
22

Добавьте команду Expect 'interact' непосредственно перед EOD:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
expect "password"
send "$PWD\n"
interact
EOD
echo "you're out"

Это должно позволить вам взаимодействовать с удаленным компьютером, пока вы не выйдете из системы. Тогда вы вернетесь в Баш.

др-Январь
источник
Он сразу входит и уходит обратно. напечатано «вы вышли».
Эммануэль
8
Я заменил «взаимодействовать» и «EOD» на «ожидать eof», и это сработало для меня. Это на Mac.
Эммануэль
2
Ни один из ответов на этой странице не помог мне, но предложение @ Emmanuel об использовании expect eofрешило проблему.
Moertel
Удалите 'из, usr@$myhost.example.com'и он должен работать. И, возможно, вам нужно заменить \nна \r, но YMMV
Tino
20

Я месяцами искал ответ на вопрос и наконец нашел действительно лучшее решение: написать простой сценарий.

#!/usr/bin/expect

set timeout 20

set cmd [lrange $argv 1 end]
set password [lindex $argv 0]

eval spawn $cmd
expect "Password:"
send "$password\r";
interact

Положите его /usr/bin/exp, тогда вы можете использовать:

  • exp <password> ssh <anything>
  • exp <password> scp <anysrc> <anydst>

Готово!

damn_c
источник
expect "assword:"ты имел ввиду expect "password:"?
пользователь
1
@user "assword"будет соответствовать обоим Passwordи password.
Ferdinand.kraft
8

Также обязательно используйте

send -- "$PWD\r"

вместо этого, поскольку пароли, начинающиеся с тире (-), в противном случае не будут работать.

Вышеупомянутое не будет интерпретировать строку, начинающуюся с тире, как параметр для команды отправки.

Timmah
источник
8

Простой скрипт Expect:

Файл Remotelogin.exp

    #!/usr/bin/expect
    set user [lindex $argv 1]
    set ip [lindex $argv 0]
    set password [lindex $argv 2]
    spawn ssh $user@$ip
    expect "password"
    send "$password\r"
    interact

Пример:

./Remotelogin.exp <ip> <user name> <password>
Виджай С.Б.
источник
7

Используйте вспомогательный инструмент fd0ssh(из hxtools, а не pmt). Он работает, не ожидая от sshпрограммы конкретного запроса .

user562374
источник
Это круто! Немного сложно заставить его работать (по крайней мере, на сервере ubuntu), но работает плавно! Сделанный echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port user@yourserver.com & конфиг : СПАСИБО!
JP Illanes
1
Намного безопаснее, чем передавать пароль в командной строке sshpass.
Чарльз Даффи
5

Другой способ, который я нашел полезным использовать небольшой сценарий Expect из сценария Bash, заключается в следующем.

...
Bash script start
Bash commands
...
expect - <<EOF
spawn your-command-here
expect "some-pattern"
send "some-command"
...
...
EOF
...
More Bash commands
...

Это работает, потому что ...If the string "-" is supplied as a filename, standard input is read instead...

Джимбо
источник
Здесь вам не нужно -, так как по умолчанию expectчитается stdin, если вы вызываете его без аргументов. Однако это полезно, если вы хотите запустить его в интерактивном режиме без командной строки ( expectvs. expect -) или если вы делаете что-то вроде того, expect -f "$@"где первым аргументом должен быть файл, даже если он выглядит как опция (начинается с -). В этом случае, если $1(данный файл) -это читается из stdin.
Tino
1

sshpassне работает, если вы попытаетесь использовать его внутри цели сборки Sublime Text , внутри Makefile. Вместо этого sshpassвы можете использовать passh: https://github.com/clarkwang/passh

С sshpassвами сделали бы:

sshpass -p pa$$word ssh user@host

С passhвами сделали бы:

passh -p pa$$word ssh user@host

Примечание: не забывайте использовать -o StrictHostKeyChecking=no. В противном случае соединение будет зависать при первом использовании. Например:

passh -p pa$$word ssh -o StrictHostKeyChecking=no user@host

Ссылки:

  1. Команда отправки пароля не работает с использованием сценария Expect в SSH-соединении
  2. Как отключить строгую проверку ключа хоста в ssh?
  3. Как отключить проверку ключа хоста SSH
  4. scp без проверки known_hosts
  5. pam_mount и sshfs с аутентификацией по паролю
пользователь
источник