Running remote commands and piping data

SSH · Essentials · 8 min

One-off remote commands and pipes over SSH are the backbone of scripts, backups and quick checks.

Give ssh a command after the host and it runs that command instead of an interactive shell, then exits with the command's exit status:

ssh web1 'df -h /' prints the disk usage and returns.

Quoting matters. The command string is sent to the remote shell, so quote it to stop your local shell from expanding things: ssh web1 'echo $HOME' prints the remote home, while ssh web1 "echo $HOME" prints your local one.

Standard input and output are connected through the tunnel, which makes ssh a pipe:

  • ssh db 'pg_dump shop' > shop.sql streams a dump to your machine.
  • tar czf - project | ssh backup 'cat > project.tgz' sends an archive the other way.
  • ssh web1 'journalctl -u nginx -n 100' | grep 500 filters remote logs locally.

When you pass a command, ssh does not allocate a terminal, which is right for pipes. Interactive programs (top, sudo asking for a password, vim, tmux) need one: add -t.

Exit status propagates, so scripts can use it: ssh web1 'systemctl is-active nginx' || alert. For running the same command on many hosts, a simple loop works; tools like Ansible build on exactly this.

Example

ssh web1 'uptime'                         # runs remotely, prints, exits
ssh web1 'echo $HOME'                     # /home/alice  (remote)
ssh web1 "echo $HOME"                     # expanded locally first!
ssh -t web1 'sudo systemctl restart nginx'   # needs a TTY for sudo prompt
ssh db 'pg_dump shop | gzip' > shop.sql.gz   # stream remote -> local
tar czf - src | ssh backup 'cat > src.tgz'   # stream local -> remote
for h in web1 web2; do ssh "$h" 'hostname; uptime'; done
ssh web1 'test -f /etc/maintenance' && echo "in maintenance"

Remember

  • ssh host 'cmd' returns the command's output and exit status
  • Single-quote the command so the remote shell expands it
  • Add -t for interactive programs; leave it off for pipes

Watch out for

  • Using double quotes and getting local variable expansion instead of remote.

Check yourself

  1. Why does `ssh host "echo $USER"` print your local username?
  2. Which flag do you need for `ssh host 'htop'` to work?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: man.openbsd.org/ssh