How can I detect if the shell is controlled from SSH?

Here are the criteria I use in my ~/.profile:

  • If one of the variables SSH_CLIENT or SSH_TTY is defined, it's an ssh session.
  • If the login shell's parent process name is sshd, it's an ssh session.
if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
  SESSION_TYPE=remote/ssh
# many other tests omitted
else
  case $(ps -o comm= -p $PPID) in
    sshd|*/sshd) SESSION_TYPE=remote/ssh;;
  esac
fi

(Why would you want to test this in your shell configuration rather than your session startup?)


You should be able to check via the SSH_TTY, SSH_CONNECTION, or SSH_CLIENT variables.


I just had the same problem in Linux, using Bash. I first used the environment variable SSH_CONNECTION, but then realized that it is not set if you su -.

The lastlog solution above didn't work either after su or su -.

Finally, I am using who am i, which shows the remote IP (or the hostname) at the end if it's an SSH connection. It also works after su.

Using Bash regular expressions, this works:

if [[ $(who am i) =~ \([-a-zA-Z0-9\.]+\)$ ]] ; then echo SSH; else echo no; fi

If zsh doesn't support regular expressions, the same can be achieved in many different ways with grep, cut, sed, or whatever.

For the curious, below is what I use this for, in root's .bashrc :

    # We don't allow root login over ssh.
    # To enable root X forwarding if we are logged in over SSH, 
    # use the .Xauthority file of the user who did su

    w=$(who am i)
    if [[ $w =~ \([-a-zA-Z0-9\.]+\)$ ]] ; then
        olduser=${w/ .*/}
        oldhome=$(getent passwd $olduser | cut -d: -f 6)
        [ -f "$oldhome/.Xauthority" ] \
          && export XAUTHORITY=$oldhome/.Xauthority
    fi

An alternative which also works with su would be to recursively search for sshd through the parent processes:

#!/bin/bash

function is_ssh() {
  p=${1:-$PPID}
  read pid name x ppid y < <( cat /proc/$p/stat )
  # or: read pid name ppid < <(ps -o pid= -o comm= -o ppid= -p $p) 
  [[ "$name" =~ sshd ]] && { echo "Is SSH : $pid $name"; return 0; }
  [ "$ppid" -le 1 ]     && { echo "Adam is $pid $name";  return 1; }
  is_ssh $ppid
}

is_ssh $PPID
exit $?

If the function is added to .bashrc, it can be used as if is_ssh; then ...