When developing portable bash configurations across multiple machines, session context detection becomes crucial. The primary issue arises when environment variables like SSH_CLIENT
get stripped during privilege escalation or shell transitions. Here's a comprehensive approach to robust SSH session detection.
The most reliable approach examines several SSH-related environment variables:
if [ -n "$SSH_CONNECTION" ] || [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
IS_SSH_SESSION=true
else
case $(ps -o comm= -p $PPID 2>/dev/null) in
sshd|*/sshd) IS_SSH_SESSION=true;;
esac
fi
When environment variables aren't available, we can examine the process tree:
is_ssh_session() {
# Check if we're in a tmux/screen session first
if [ -n "$TMUX" ] || [ -n "$STY" ]; then
pstree -s $$ | grep -q sshd
return $?
else
# Direct SSH session check
[ -n "$SSH_TTY" ] || ps -o comm= -p $PPID | grep -q sshd
fi
}
To maintain SSH detection across sudo sessions without preserving the entire environment:
check_ssh_origin() {
local pid=$$
while [ $pid -ne 1 ]; do
if ps -p $pid -o comm= | grep -q sshd; then
return 0
fi
pid=$(ps -o ppid= -p $pid)
done
return 1
}
Here's how to integrate this into your bashrc for conditional aliases:
# In ~/.bashrc or your shell config
if is_ssh_session; then
alias reboot='echo "SSH session detected - use physical console for reboot"'
alias halt='echo "SSH session detected - use physical console for shutdown"'
else
alias reboot='sudo /sbin/reboot'
alias halt='sudo /sbin/halt'
fi
For systems where process inspection isn't reliable, consider these methods:
# TTY-based detection
if tty | grep -q '^/dev/pts/'; then
# Likely SSH session (pseudo-terminal)
fi
# Terminal emulator check
if [[ "$TERM" == "xterm-256color" && -n "$SSH_CONNECTION" ]]; then
# SSH session with color support
fi
- Containerized environments may require additional checks
- Jump hosts or SSH tunnels might obscure the original connection
- Some sudo configurations preserve SSH environment variables
- Consider adding a manual override variable for edge cases
When working with remote servers, it's often useful to determine whether your current shell session was initiated via SSH. This can help customize your environment—for instance, disabling dangerous commands like halt
on remote systems. The most common method involves checking environment variables set by the SSH daemon.
if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
echo "This is an SSH session."
# Customize remote aliases/behavior
alias halt='echo "Command disabled on remote systems!"'
else
echo "Local shell session detected."
fi
The primary variables (SSH_CLIENT
, SSH_CONNECTION
, SSH_TTY
) are discarded during sudo
operations unless explicitly preserved. To handle this:
# Option 1: Use sudo -E to preserve environment
sudo -E bash -c 'echo $SSH_CLIENT'
# Option 2: Check parent processes
if ps -o comm= -p $PPID | grep -q sshd; then
echo "SSH session (via process check)"
fi
For systems where environment variables are unavailable, consider these approaches:
# Method 1: Check tty name (SSH sessions often use /dev/pts/*)
if [[ $(tty) =~ /dev/pts/[0-9]+ ]]; then
echo "Likely SSH session"
fi
# Method 2: Parse netstat/lsof for SSH connections
if lsof -iTCP -sTCP:ESTABLISHED -p $$ | grep -q sshd; then
echo "Active SSH connection detected"
fi
# Method 3: Systemd-specific check (Linux)
if [ -n "$XDG_SESSION_TYPE" ] && [ "$XDG_SESSION_TYPE" = "tty" ]; then
echo "Local session"
elif systemctl --user show-environment | grep -q SSH_CONNECTION; then
echo "SSH session via systemd"
fi
Here's a consolidated solution for your bash configuration:
# ~/.bashrc snippet
function is_ssh_session() {
[[ -n "$SSH_CLIENT" || -n "$SSH_TTY" ]] || \
ps -o comm= -p $PPID | grep -q sshd || \
[[ $(tty) =~ /dev/pts/[0-9]+ ]]
}
if is_ssh_session; then
alias halt='echo "Remote system protection: halt disabled"'
export PS1="$$\e[1;31m$$[SSH]$$\e[0m$$ \u@\h:\w\$ "
fi