54
votes

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?

10
Try $SSH_AGENT_PID.choroba
If you want to kill a process after spawning it, you can store its PID into a variable and call it like so: kill -9 $PID_SSH_AGENTalok
I think making the script responsible for starting an agent is the wrong approach. Just assume that an agent is running, and require any user to ensure that they have an agent already (usually started by your initial login shell.)chepner
You could also simply run such a script with ssh-agent my-script to start an agent that exits as soon as my-script exits.chepner
I cannot do that since login to the machine multiple times a day - and not just me, but other people as well.Zlatan Omerović

10 Answers

50
votes

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: https://stackoverflow.com/a/15774758

35
votes

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).

12
votes

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).

4
votes

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 !!!

4
votes

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

2
votes

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
0
votes

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
0
votes

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

0
votes

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[@]}"

0
votes
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.