28

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?

  • Do you want an interactive SSH session? – Nobody Nov 16 '17 at 20:48
  • @Nobody yes I do – Philip Kirkbride Nov 16 '17 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 '17 at 21:11
29

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
}
  • 1
    thanks, I'm going to use the repeat script but with $ instead of the prompt :-) – Philip Kirkbride Nov 15 '17 at 18:00
  • 14
    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. – Austin Hemmelgarn Nov 15 '17 at 20:22
17
ssh me@device.local
until !!; do sleep 5 ; done

The !! to repeat the last command.

  • 4
    Creative use of the shell history! +1 – David Foerster Nov 16 '17 at 11:30
14

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.

  • This doesn't seem to be working for me :/ – Freedo Aug 17 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. – David Foerster 2 days ago
13
while ! ssh user@host.example.com true; do
    sleep 5
done; echo "Host is back up at $(date)!"
  • 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 '17 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.