How to check if ssh-agent is already running in bash?

LinuxBashShellSsh

Linux Problem Overview


I have a sample sh script on my Linux environment, which basically run's the ssh-agent for the current shell, adds a key to it and runs two git commands:

#!/bin/bash
eval "$(ssh-agent -s)"
ssh-add /home/duvdevan/.ssh/id_rsa

git -C /var/www/duvdevan/ reset --hard origin/master
git -C /var/www/duvdevan/ pull origin master

Script actually works fine, but every time I run it I get a new process so I think it might become a performance issue and I might end up having useless processes out there.

An example of the output:

Agent pid 12109
Identity added: /home/duvdevan/.ssh/custom_rsa (rsa w/o comment)

Also, along with all this, is it possible to find an existing ssh-agent process and add my keys into it?

Linux Solutions


Solution 1 - Linux

No, really, how to check if ssh-agent is already running in bash?

Answers so far don't appear to answer the original question...

Here's what works for me:

if ps -p $SSH_AGENT_PID > /dev/null
then
   echo "ssh-agent is already running"
   # Do something knowing the pid exists, i.e. the process with $PID is running
else
eval `ssh-agent -s`
fi

This was taken from here

Solution 2 - Linux

> Also, along with all this, is it possible to find an existing ssh-agent process and add my keys into it?

Yes. We can store the connection info in a file:

# Ensure agent is running
ssh-add -l &>/dev/null
if [ "$?" == 2 ]; then
    # Could not open a connection to your authentication agent.

    # Load stored agent connection info.
    test -r ~/.ssh-agent && \
        eval "$(<~/.ssh-agent)" >/dev/null

    ssh-add -l &>/dev/null
    if [ "$?" == 2 ]; then
        # Start agent and store agent connection info.
        (umask 066; ssh-agent > ~/.ssh-agent)
        eval "$(<~/.ssh-agent)" >/dev/null
    fi
fi

# Load identities
ssh-add -l &>/dev/null
if [ "$?" == 1 ]; then
    # The agent has no identities.
    # Time to add one.
    ssh-add -t 4h
fi

This code is from pitfalls of ssh agents which describes both the pitfalls of what you're currently doing, of this approach, and how you should use ssh-ident to do this for you.


If you only want to run ssh-agent if it's not running and do nothing otherwise:

if [ $(ps ax | grep [s]sh-agent | wc -l) -gt 0 ] ; then
    echo "ssh-agent is already running"
else
    eval $(ssh-agent -s)
    if [ "$(ssh-add -l)" == "The agent has no identities." ] ; then
        ssh-add ~/.ssh/id_rsa
    fi

    # Don't leave extra agents around: kill it on exit. You may not want this part.
    trap "ssh-agent -k" exit
fi

However, this doesn't ensure ssh-agent will be accessible (just because it's running doesn't mean we have $SSH_AGENT_PID for ssh-add to connect to).

Solution 3 - Linux

If you want it to be killed right after the script exits, you can just add this after the eval line:

trap "kill $SSH_AGENT_PID" exit

Or:

trap "ssh-agent -k" exit

$SSH_AGENT_PID gets set in the eval of ssh-agent -s.

You should be able to find running ssh-agents by scanning through /tmp/ssh-* and reconstruct the SSH_AGENT variables from it (SSH_AUTH_SOCK and SSH_AGENT_PID).

Solution 4 - Linux

ps -p $SSH_AGENT_PID > /dev/null || eval "$(ssh-agent -s)"

Single line command. Run for the first time will start ssh-agent. Run for the second time will not start the ssh-agent. Simple and Elegant Mate !!!

Solution 5 - Linux

Using $SSH_AGENT_PID can only test the ssh-agent but miss identities when it is not yet added

$ eval `ssh-agent`
Agent pid 9906
$ echo $SSH_AGENT_PID
9906
$ ssh-add -l
The agent has no identities.

So it would be save to check it with ssh-add -l with an expect script like example below:

$ eval `ssh-agent -k`
Agent pid 9906 killed
$ ssh-add -l
Could not open a connection to your authentication agent.
$ ssh-add -l &>/dev/null
$ [[ "$?" == 2 ]] && eval `ssh-agent`
Agent pid 9547
$ ssh-add -l &>/dev/null
$ [[ "$?" == 1 ]] && expect $HOME/.ssh/agent
spawn ssh-add /home/user/.ssh/id_rsa
Enter passphrase for /home/user/.ssh/id_rsa: 
Identity added: /home/user/.ssh/id_rsa (/home/user/.ssh/id_rsa)
$ ssh-add -l
4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /home/user/.ssh/id_rsa (RSA)

So when both ssh-agent and ssh-add -l are put to run on a bash script:

#!/bin/bash
ssh-add -l &>/dev/null
[[ "$?" == 2 ]] && eval `ssh-agent`
ssh-add -l &>/dev/null
[[ "$?" == 1 ]] && expect $HOME/.ssh/agent

then it would always check and assuring that the connection is running:

$ ssh-add -l
4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /home/user/.ssh/id_rsa (RSA)

You can also emulate the repeating of commands on above script with do while

Solution 6 - Linux

The accepted answer did not work for me under Ubuntu 14.04.

The test to check if the ssh-agent is running I have to use is:

[[ ! -z ${SSH_AGENT_PID+x} ]]

And I am starting the ssh-agent with:

exec ssh-agent bash

Otherwise the SSH_AGENT_PID is not set.

The following seems to work under both Ubuntu 14.04 and 18.04.

#!/bin/bash
sshkey=id_rsa
# Check ssh-agent
if [[ ! -z ${SSH_AGENT_PID+x} ]]
then
    echo "[OK] ssh-agent is already running with pid: "${SSH_AGENT_PID}
else
    echo "Starting new ssh-agent..."
    `exec ssh-agent bash`
    echo "Started agent with pid: "${SSH_AGENT_PID}
fi
# Check ssh-key
if [[ $(ssh-add -L | grep ${sshkey} | wc -l) -gt 0 ]]
then
    echo "[OK] SSH key already added to ssh-agent"
else
    echo "Need to add SSH key to ssh-agent..."
    # This should prompt for your passphrase
    ssh-add ~/.ssh/${sshkey}
fi

Solution 7 - Linux

I've noticed that having a running agent is not enough because sometimes, the SSH_AUTH_SOCK variable is set or pointing to a socket file that does not exist anymore.

Therefore, to connect to an already running ssh-agent on your machine, you can do this :

$ pgrep -u $USER -n ssh-agent -a
1906647 ssh-agent -s
$ ssh-add -l
Could not open a connection to your authentication agent.
$ test -z "$SSH_AGENT_PID" && export SSH_AGENT_PID=$(pgrep -u $USER -n ssh-agent)
$ test -z "$SSH_AUTH_SOCK" && export SSH_AUTH_SOCK=$(ls /tmp/ssh-*/agent.$(($SSH_AGENT_PID-1)))
$ ssh-add -l
The agent has no identities.

Solution 8 - Linux

cat /usr/local/bin/ssh-agent-pro << 'EOF'
#!/usr/bin/env bash
SSH_AUTH_CONST_SOCK="/var/run/ssh-agent.sock"

if [[ x$(wc -w <<< $(pidof ssh-agent)) != x1 ]] || [[ ! -e ${SSH_AUTH_CONST_SOCK} ]]; then
  kill -9 $(pidof ssh-agent) 2>/dev/null
  rm -rf ${SSH_AUTH_CONST_SOCK}
  ssh-agent -s -a ${SSH_AUTH_CONST_SOCK} 1>/dev/null
fi

echo "export SSH_AUTH_SOCK=${SSH_AUTH_CONST_SOCK}"
echo "export SSH_AGENT_PID=$(pidof ssh-agent)"
EOF
echo "eval \$(/usr/local/bin/ssh-agent-pro)" >> /etc/profile
. /etc/profile

then you can ssh-add xxxx once, you can use ssh-agent everytime when you login.

Solution 9 - Linux

Regarding finding running ssh-agents, previous answers either don't work or rely on a magic file like $HOME/.ssh_agent. These approaches require us to believe that user never run agents without saving their output to this file.

My approach instead relies on a rarely changed default UNIX domain socket template to find an accessible ssh-agent among available possibilities.

# (Paste the below code to your ~/.bash_profile and ~/.bashrc files)
C=$SSH_AUTH_SOCK
R=n/a
unset SSH_AUTH_SOCK
for s in $(ls $C /tmp/ssh-*/agent.* 2>/dev/null | sort -u) ; do
  if SSH_AUTH_SOCK=$s ssh-add -l >/dev/null ; then R=$? ; else R=$? ; fi
  case "$R" in
    0|1) export SSH_AUTH_SOCK=$s ; break ;;
  esac
done
if ! test -S "$SSH_AUTH_SOCK" ; then
  eval $(ssh-agent -s)
  unset SSH_AGENT_PID
  R=1
fi
echo "Using $SSH_AUTH_SOCK"
if test "$R" = "1" ; then
  ssh-add
fi

In this approach, SSH_AGENT_PID remains unknown, since it is hard to deduce it for non-roots. I assume it is actually not required for users since they don't normally want to stop agents. On my system, setting SSH_AUTH_SOCK is enough to communicate with agent for e.g. passwordless authentication. The code should work with any shell-compatible shell.

Solution 10 - Linux

You can modify line #1 to:

PID_SSH_AGENT=`eval ssh-agent -s | grep -Po "(?<=pid\ ).*(?=\;)"`

And then at the end of the script you can do:

kill -9 $PID_SSH_AGENT

Solution 11 - Linux

Thanks to all the answers here. I've used this thread a few times over the years to tweak my approach. Wanted to share my current ssh-agent.sh checker/launcher script that works for me on Linux and OSX.

The following block is my $HOME/.bash.d/ssh-agent.sh

function check_ssh_agent() {
  if [ -f $HOME/.ssh-agent ]; then
    source $HOME/.ssh-agent > /dev/null
  else
    # no agent file
    return 1
  fi

  if [[ ${OSTYPE//[0-9.]/} == 'darwin' ]]; then
    ps -p $SSH_AGENT_PID > /dev/null  
    # gotcha: does not verify the PID is actually an ssh-agent
    # just that the PID is running
    return $?
  fi

  if [ -d /proc/$SSH_AGENT_PID/ ]; then
    # verify PID dir is actually an agent
    grep ssh-agent /proc/$SSH_AGENT_PID/cmdline  > /dev/null  2> /dev/null; 
    if [ $? -eq 0 ]; then
      # yep - that is an agent
      return 0
    else
      # nope - that is something else reusing the PID
      return 1
    fi
  else
    # agent PID dir does not exist - dead agent
    return 1
  fi 
}

function launch_ssh_agent() {
  ssh-agent > $HOME/.ssh-agent
  source $HOME/.ssh-agent
  # load up all the pub keys
  for I in $HOME/.ssh/*.pub ; do
    echo adding ${I/.pub/}
    ssh-add ${I/.pub/}
  done
}

check_ssh_agent
if [ $? -eq 1 ];then
  launch_ssh_agent
fi

I launch the above from my .bashrc using:

if [ -d $HOME/.bash.d ]; then
  for I in $HOME/.bash.d/*.sh; do
    source $I  
  done
fi

Hope this helps others get up and going quickly.

Created a public gist if you want to hack/improve this with me: https://gist.github.com/dayne/a97a258b487ed4d5e9777b61917f0a72

Solution 12 - Linux

I made this bash function to count and return the number of running ssh-agent processes... it searches ssh-agent process using procfs instead of using $ ps -p $SSH_AGENT_PID:cmd or $SSH_AUTH_SOCK:var ... (these ENV-var. can still be set with old values while ssh-agent's process is already killed: if $ ssh-agent -k or $ $(ssh-agent -k) instead of $ eval $(ssh-agent -k))

function count_agent_procfs(){
    declare -a agent_list=( ) 
    for folders in $(ls -d /proc/*[[:digit:]] | grep -v /proc/1$);do
        fichier="${folders}/stat"
        pid=${folders/\/proc\//}
        [[ -f ${fichier} ]] && [[ $(cat ${fichier} | cut -d " " -f2) == "(ssh-agent)" ]] && agent_list+=(${pid})
    done
    return ${#agent_list[@]}
}

..and then if there is a lot of ssh-agent process running you get their PID with this list..."${agent_list[@]}"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZlatan OmerovićView Question on Stackoverflow
Solution 1 - LinuxAndrewDView Answer on Stackoverflow
Solution 2 - LinuxidbriiView Answer on Stackoverflow
Solution 3 - LinuxFriekView Answer on Stackoverflow
Solution 4 - LinuxicemanView Answer on Stackoverflow
Solution 5 - LinuxeQ19View Answer on Stackoverflow
Solution 6 - LinuxSveborKView Answer on Stackoverflow
Solution 7 - LinuxSebMaView Answer on Stackoverflow
Solution 8 - LinuxzwtopView Answer on Stackoverflow
Solution 9 - LinuxGrwlfView Answer on Stackoverflow
Solution 10 - LinuxalokView Answer on Stackoverflow
Solution 11 - LinuxDayne BrodersonView Answer on Stackoverflow
Solution 12 - Linuxtrollo974View Answer on Stackoverflow