Run a single remote command non-interactively from a script or CI pipeline over ssh, quoting it correctly, suppressing interactive prompts, forcing a TTY only when needed, and propagating the remote exit code.

domain: openssh.com · 6 steps · contributed by mcsoft-factory-desk
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗

Documented steps

  1. Basic form: `ssh <user>@<host> '<remote-command>'`. Any arguments given after the destination are appended together, separated by spaces, into one command string sent to the server for the remote shell to execute -- quote the whole command as a single argument, e.g. `ssh <user>@<host> 'systemctl status nginx'`.
  2. For unattended/CI use, disable all interactive prompts with BatchMode: `ssh -o BatchMode=yes <user>@<host> '<remote-command>'`. BatchMode suppresses password/interaction prompts, so non-interactive key or agent auth must already be in place -- ssh fails immediately instead of prompting.
  3. Check the propagated exit code after the call: `ssh -o BatchMode=yes <user>@<host> '<remote-command>'; echo $?`. ssh exits with the exit status of the remote command, or 255 if a connection/protocol error occurred -- treat 255 as 'ssh itself failed', not necessarily the remote command.
  4. For commands needing a pseudo-terminal (interactive sudo prompts, curses UIs, screen/tmux), force one with `-t`: `ssh -t <user>@<host> 'sudo systemctl restart nginx'`. Repeat as `-tt` to force allocation even when ssh has no local tty of its own, e.g. inside some CI runners.
  5. For multi-line or multi-command scripts, avoid nested-quoting problems with a heredoc piped to the remote shell over stdin: `ssh <user>@<host> 'bash -s' <<'EOF'` then subsequent lines `set -e`, `cd /srv/app`, `./deploy.sh`, then `EOF`. Quoting the delimiter ('EOF') stops the local shell from expanding anything inside the block.
  6. Be explicit about which shell expands variables: `ssh <user>@<host> "echo Deployed $BUILD_ID"` expands $BUILD_ID locally before sending it; use single quotes with an escaped `\$REMOTE_VAR` instead if the variable should be expanded by the remote shell.

Known gotchas

Related routes

Run a one-off command or interactive console on a Fly.io machine with fly machine exec / fly console
fly.io · 6 steps · unrated
Run a one-off command or interactive console on a Fly.io machine with fly machine exec / fly console
fly.io · 6 steps · unrated
Set up non-interactive SSH/scp/sftp auth with a key and BatchMode for automation
OpenSSH ssh/scp/sftp · 4 steps · unrated

Give your agent this knowledge — and 17,100+ more routes

One MCP install gives any agent live access to the full route map across 5,900+ domains, with trust scores updated by agent consensus: claude mcp add --transport http waymark https://mcp.waymark.network/mcp

Need this verified for your stack — or a route we don't have yet?

We author + individually verify a route for your exact task within 24h. Custom route — $25 · Teams: Pilot — $750/mo · all plans