46

Sometimes I restart a device and need to ssh back in when it's ready.

I want to run the ssh command every 5 seconds until the command succeeds.

My first attempt:

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

How can I do this?

3
  • Do you want an interactive SSH session?
    – Nobody
    Nov 16, 2017 at 20:48
  • @Nobody yes I do Nov 16, 2017 at 20:49
  • Ok, I first thought my idea wouldn't work interactively, but a short test showed that it does so I wrote an answer anyway. :)
    – Nobody
    Nov 16, 2017 at 21:11

6 Answers 6

50

Another option would be to use until.

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

If you do this repeatedly for a number of hosts, put it in a function in your ~/.bashrc.

repeat()
{
read -p "Enter the hostname or IP of your server :" servername
until ssh $servername; do
    sleep 5
done
}
2
  • 1
    thanks, I'm going to use the repeat script but with $ instead of the prompt :-) Nov 15, 2017 at 18:00
  • 16
    It is worth noting that ssh can exit with a non-zero status after having connected successfully if something external to the connection terminates the session, in which case that script will attempt to reconnect. This may or may not be a desirable side effect. Nov 15, 2017 at 20:22
35
ssh me@device.local
until !!; do sleep 5 ; done

The !! to repeat the last command.

2
  • 8
    Creative use of the shell history! +1 Nov 16, 2017 at 11:30
  • 1
    Two things: 1. I love the simplicity and cleverness, and 2. This will also reconnect to a host that reboots. It kills two birds with one stone. Double bonus! May 16 at 17:32
28

OpenSSH has a ConnectionAttempts setting that does almost what you want. The default is 1 but you can change it in ssh_config or on the command-line:

ssh -o 'ConnectionAttempts 10' ...

Unfortunately you can't adjust the attempt interval which is fixed at 1 second, but you can adjust the connection attempt time-out ConnectTimeout (in seconds) in the same fashion.

4
  • This doesn't seem to be working for me :/
    – Freedo
    Aug 17, 2019 at 10:57
  • @Freedo: Could you please explain what exactly you tried and what exactly didn't work? Also, it would likely be better to write a new question about your issue. You're welcome to draw my attention to it through a a link in the comments. Aug 18, 2019 at 11:36
  • If it wasn't for the spurious (in my opinion) 5 second interval, this would be the correct answer. It certainly gets my upvote. A suggested addition to make the thing even more convenient, put this ... alias YH="ssh -o 'ConnectionAttempts 20' you@yourhost" ... in your ${HOME}/.profile. Then, after reboot, you'd just have to type YH on the command line, pour another coffee, take a sip ... and you're in. Jul 21, 2020 at 16:23
  • created bash fn sshr() { ssh $1 -o "ConnectionAttempts 10" } so I can do this sshr destination
    – John Lee
    Feb 16 at 22:44
15
while ! ssh user@host.example.com true; do
    sleep 5
done; echo "Host is back up at $(date)!"
1
  • 2
    Or, if you don't want to actually log in until the service is up, while ! nc -w5 -z host.example.com 22; do [...].
    – DopeGhoti
    Nov 15, 2017 at 17:46
4

autossh keeps ssh sessions alive. With the right parameters you can also launch it when it's currently impossible to connect and it will try until it succeeds. This works fine, but if you want the reconnect part to work nicely with interactive sessions you'll need to combine it with screen or equivalent.

I recommend this:

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

But see its man page for details. With the above parameters, autossh will try launching ssh every AUTOSSH_POLL seconds, AUTOSSH_GATETIME=0 makes it try again if the first try fails (so definitely what you want), -M 0 disables connection checking by autossh, all later options are passed to ssh. The two -o options make ssh exit if the connections drops for more than 5s.

2

At the risk of just throwing code at an answer, this script works for me on a daily basis. I call it ressh and it can be used as simply as ressh {hostname}, or with care, 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.