Skip to content

Instantly share code, notes, and snippets.

@mevanlc
Created April 16, 2026 18:49
Show Gist options
  • Select an option

  • Save mevanlc/db12574c0b7e49ba54f487ffb0cbbe0d to your computer and use it in GitHub Desktop.

Select an option

Save mevanlc/db12574c0b7e49ba54f487ffb0cbbe0d to your computer and use it in GitHub Desktop.
sshforce = ssh wrapper that doesn't care about fingerprint changes (add -Z to retry connecting indefinitely)
#!/usr/bin/env bash
set -euo pipefail
if [ "$#" -eq 0 ]; then
echo "Usage: sshforce [-Z] [ssh flags] <hostname> [ssh flags]" >&2
exit 1
fi
# ssh short flags that consume the following argument as a value
value_flags='BbcDEeFIiJLlmOopQRSWw'
hostname=""
port=""
retry=0
filtered_args=()
args=("$@")
i=0
while [ $i -lt ${#args[@]} ]; do
arg="${args[$i]}"
if [[ "$arg" == -- ]]; then
filtered_args+=("$arg")
i=$((i + 1))
if [ $i -lt ${#args[@]} ] && [ -z "$hostname" ]; then
hostname="${args[$i]}"
fi
while [ $i -lt ${#args[@]} ]; do
filtered_args+=("${args[$i]}")
i=$((i + 1))
done
break
fi
if [[ "$arg" == "-Z" ]]; then
retry=1
i=$((i + 1))
continue
fi
if [[ "$arg" == -* ]]; then
if [ ${#arg} -eq 2 ] && [[ "$value_flags" == *"${arg:1:1}"* ]]; then
if [ "$arg" = "-p" ] && [ $((i + 1)) -lt ${#args[@]} ]; then
port="${args[$((i + 1))]}"
fi
filtered_args+=("$arg")
if [ $((i + 1)) -lt ${#args[@]} ]; then
filtered_args+=("${args[$((i + 1))]}")
fi
i=$((i + 2))
continue
fi
filtered_args+=("$arg")
i=$((i + 1))
continue
fi
if [ -z "$hostname" ]; then
hostname="$arg"
fi
filtered_args+=("$arg")
i=$((i + 1))
done
if [ -z "$hostname" ]; then
echo "sshforce: could not locate hostname in args" >&2
exit 1
fi
# strip user@ prefix for the known_hosts lookup
host_only="${hostname#*@}"
if [ -n "$port" ] && [ "$port" != "22" ]; then
ssh-keygen -R "[$host_only]:$port"
else
ssh-keygen -R "$host_only"
fi
if [ "$retry" -eq 0 ]; then
exec ssh -o StrictHostKeyChecking=accept-new "${filtered_args[@]}"
fi
while true; do
rc=0
ssh -o StrictHostKeyChecking=accept-new "${filtered_args[@]}" || rc=$?
# ssh returns 255 on connection failure; other codes come from the remote side
if [ "$rc" -ne 255 ]; then
exit "$rc"
fi
sleep 1
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment