Created
April 16, 2026 18:49
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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