Как запустить команду SSH, пока не удалось?

28

Иногда я перезагружаю устройство и мне нужно sshвернуться, когда оно будет готово.

Я хочу запускать команду ssh каждые 5 секунд, пока команда не будет выполнена успешно.

Моя первая попытка:

watch -n5 ssh me@device.local && exit 1

Как я могу это сделать?

Филип Киркбрайд
источник
Хотите интерактивную сессию SSH?
Никто
@ Никто да, я делаю
Филипп Киркбрайд
Хорошо, я сначала подумал, что моя идея не будет работать в интерактивном режиме, но короткий тест показал, что она работает, поэтому я все равно написал ответ. :)
Никто

Ответы:

30

Другой вариант будет использовать until.

until ssh me@device.local; do
    sleep 5
done

Если вы делаете это несколько раз для нескольких хостов, поместите это в функцию в вашем ~/.bashrc.

repeat()
{
read -p "Enter the hostname or IP of your server :" servername
until ssh $servername; do
    sleep 5
done
}
Hunter.S.Thompson
источник
1
спасибо, я собираюсь использовать скрипт повтора, но $вместо подсказки :-)
Филипп Киркбрайд
14
Стоит отметить, что sshпосле успешного подключения может выйти с ненулевым состоянием, если что-то внешнее по отношению к соединению завершит сеанс, и в этом случае этот сценарий попытается восстановить соединение. Это может или не может быть желательным побочным эффектом.
Остин Хеммельгарн
17
ssh me@device.local
until !!; do sleep 5 ; done

!!Повторить последнюю команду.

GAD3R
источник
4
Творческое использование истории оболочки! +1
Дэвид Фёрстер
15

OpenSSH имеет ConnectionAttemptsнастройку, которая делает почти то, что вы хотите. По умолчанию это 1, но вы можете изменить его в ssh_configкомандной строке или в командной строке:

ssh -o 'ConnectionAttempts 10' ...

К сожалению, вы не можете настроить интервал попыток, который установлен равным 1 секунде, но вы можете настроить время ожидания попытки подключения ConnectTimeout(в секундах) таким же образом.

Дэвид Фёрстер
источник
Это, кажется, не работает для меня: /
Freedo
@Freedo: Не могли бы вы объяснить, что именно вы пытались, а что именно не сработало? Кроме того, было бы лучше написать новый вопрос о вашей проблеме. Вы можете обратить на это мое внимание через ссылку в комментариях.
Дэвид Фёрстер
14
while ! ssh user@host.example.com true; do
    sleep 5
done; echo "Host is back up at $(date)!"
DopeGhoti
источник
2
Или, если вы не хотите входить в систему до тех пор, пока служба не будет запущена while ! nc -w5 -z host.example.com 22; do [...].
DopeGhoti
4

autosshподдерживает сессию SSH С правильными параметрами вы также можете запустить его, когда в настоящее время невозможно подключиться, и он будет пытаться, пока не получится. Это прекрасно работает, но если вы хотите, чтобы часть повторного подключения хорошо работала с интерактивными сеансами, вам нужно объединить ее screenили эквивалентную.

Я рекомендую это:

AUTOSSH_POLL=5 AUTOSSH_GATETIME=0 autossh -M 0 -o ServerAliveInterval=5 -o ServerAliveCountMax=1 user@host

Но смотрите его справочную страницу для деталей. С указанными выше параметрами autosshбудет пытаться запускать ssh каждую AUTOSSH_POLLсекунду, AUTOSSH_GATETIME=0повторять попытку, если первая попытка не удалась (именно то, что вам нужно), -M 0отключить проверку соединения с помощью autossh, все последующие опции передаются в ssh. Эти две -oопции заставляют ssh выйти, если соединения разрываются более чем на 5 секунд.

Никто
источник
2

С риском просто бросить код в ответ, этот скрипт работает для меня ежедневно. Я называю это, resshи это может использоваться так же просто ressh {hostname}, или с осторожностью,ressh -S {session_name} {hostname}

#!/bin/bash
#
# Repeatedly attempt to reconnect to a remote ssh server
########################################################################
#
prefix="${0/*\/}"
port=
session=
action=ssh              # How to connect remotely

while getopts 'l:Lp:P:S:' OPT
do
    case "$OPT" in
        l)      [[ s == "$OPTARG" ]] && action=list ;;
        L)      action=list ;;
        [Pp])   port="$OPTARG" ;;
        S)      session="$OPTARG";; ## ; [[ $session =~ ^[0-9]+$ ]] && session="${prefix}-$session" ;;
    esac
done
shift $(($OPTIND - 1))

host="$1"
shift

if [[ -z "$host" ]]
then
    echo "ERROR: Missing hostname" >&2
    exit 1
fi


if [[ list == "$action" ]]
then
    ssh ${port:+-p $port} "$host" "screen -ls"
    exit 0
fi

# Connect repeatedly to the target host system
#
[[ -z "$session" ]] && session="${prefix}-$$.$host"

while :
do
    ssh -tt ${port:+-p $port} "$host" "screen -dr $session || screen -S $session $*"
    ss=$?
    [[ 0 -eq $ss ]] && break

    [[ 255 -eq $ss ]] && sleep 4
    sleep 1
    echo "Reconnecting to session $session on $host..."
done


# All done
#
exit 0
roaima
источник