【问题标题】:How to check if ssh-agent is already running in bash?如何检查 ssh-agent 是否已经在 bash 中运行?
【发布时间】:2017-03-25 18:20:01
【问题描述】:

我的 Linux 环境中有一个示例 sh 脚本,它基本上运行的是当前 shell 的 ssh-agent,为其添加了一个密钥并运行两个 git 命令:

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

脚本实际上运行良好,但每次我运行它都会得到一个新进程,所以我认为它可能会成为性能问题,我可能最终会得到无用的进程。

输出示例:

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

除此之外,是否有可能找到现有的ssh-agent 进程并将我的密钥添加到其中?

【问题讨论】:

  • 试试$SSH_AGENT_PID
  • 如果你想在产生一个进程后杀死它,你可以将它的 PID 存储到一个变量中并像这样调用它:kill -9 $PID_SSH_AGENT
  • 我认为让脚本负责启动代理是错误的做法。只需假设代理 正在 运行,并要求任何用户确保他们已经拥有代理(通常由您的初始登录 shell 启动。)
  • 您也可以简单地使用ssh-agent my-script 运行这样的脚本来启动一个代理,该代理会在my-script 退出时立即退出。
  • 我不能这样做,因为每天要多次登录机器——不仅是我,其他人也是如此。

标签: linux bash shell ssh


【解决方案1】:

不,真的,如何检查 ssh-agent 是否已经在 bash 中运行?

到目前为止,答案似乎无法回答原始问题...

这对我有用:

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

【讨论】:

  • 通常不起作用。既不是图形会话(ssh-agent 在本地运行或内置在密钥管理器中),也不是与ssh -A 的会话,ssh-agent 在本地运行。正确的方法可以在the answer of idbrii
  • 可以确认SSH_AGENT_PID不可靠。在我的 Mac (High Sierra) 和 SSH OpenSSH_7.8p1 上,直接调用 ssh 连接时,例如ssh host,代理以SSH_AUTH_SOCK 启动,但不是 SSH_AGENT_PID
【解决方案2】:

除此之外,是否有可能找到现有的 ssh-agent 进程并将我的密钥添加到其中?

是的。我们可以将连接信息存储在一个文件中:

# 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

这段代码来自pitfalls of ssh agents,它描述了你目前正在做的事情、这种方法的缺陷,以及你应该如何使用ssh-ident为你做这件事。


如果您只想在 ssh-agent 未运行时运行它,否则什么都不做:

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

但是,这并不能确保 ssh-agent 可以访问(仅仅因为它正在运行并不意味着我们有 $SSH_AGENT_PID 可以连接到 ssh-add)。

【讨论】:

  • 这应该是公认的答案。 至少是前半部分,因为ssh-add -l 是测试现场代理的正确方法(I'd rather suggest timeout 0.3 ssh-add -l 因为ssh-add可以坚持饿死ssh-connections - iE in tmux)。您的第一个脚本适用于 KDE 或带有 ssh -A 的远程会话。然而,后半部分或多或少像这里的所有其他答案一样无用,因为通常没有 ssh-agent 在本地运行。顺便说一句:为什么[s]grep [s]sh-agent 而不是grep -F ssh-agent(这样可以节省一些周期)。
  • “通常没有 ssh-agent 在本地运行”——除非在 OP 的情况下,他们的问题是多个 ssh-agent。 “为什么是 [s]”——ps ax|grep -F ssh-agent 将返回 grep 进程,因为 ps 输出包含程序参数(试试看)。在正则表达式中使用字符类将阻止 grep 匹配自身。另见stackoverflow.com/a/9375940/79125
  • 这也是一个很酷的答案,因为它告诉“如何判断 ssh-agent 已死”或“如何在不知道 pid 的情况下确定 ssh-agent 是否正在运行”。将screentmux 与代理转发结合使用时才有意义。
  • 我从未考虑过使用eval "$(&lt;~/.ssh-agent)",而是更愿意使用source ~/.ssh-agent。只是好奇它是否有什么不同。
  • @chutz: eval 是 ssh-agent 文档建议的(可能是因为他们不使用中间文件),但我不确定是否有区别。这可能是一个很好的问题(我发现最接近的是this one)。
【解决方案3】:

如果你希望它在脚本退出后立即被杀死,你可以在 eval 行之后添加:

trap "kill $SSH_AGENT_PID" exit

或者:

trap "ssh-agent -k" exit

$SSH_AGENT_PID 被设置在 ssh-agent -s 的 eval 中。

您应该能够通过扫描/tmp/ssh-* 并从中重建SSH_AGENT 变量(SSH_AUTH_SOCKSSH_AGENT_PID)来找到正在运行的ssh-agents。

【讨论】:

  • 为什么我不应该在我的脚本末尾添加kill -9 $SSH_AGENT_PID,就像@alok 在他对这个问题的评论中所说的那样?
  • 如果脚本本身在运行时被终止(带有可中断信号),该命令将不会运行。有了陷阱就可以了。
  • 另外,kill -9 不应该是必要的,除非在开发过程中杀死一个错误的程序。 kill 本身在几乎所有情况下都足够了。
  • 是的。我刚刚看到ssh-agent -k 终止了进程并取消了SSH_AUTH_SOCKSSH_AGENT_PID 变量的设置——我将您的解决方案与trap 一起使用。谢谢!
【解决方案4】:

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

单行命令。第一次运行会启动 ssh-agent。第二次运行不会启动 ssh-agent。简单优雅的伴侣!!!

【讨论】:

    【解决方案5】:

    使用$SSH_AGENT_PID只能测试ssh-agent,但在尚未添加时会错过身份

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

    所以最好用ssh-add -lexpect script 来检查它,如下例所示:

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

    所以当 ssh-agentssh-add -l 都在 bash 脚本上运行时:

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

    那么它将始终检查并确保连接正在运行:

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

    您还可以使用do while模拟上述脚本上命令的重复

    【讨论】:

      【解决方案6】:

      接受的答案在 Ubuntu 14.04 下对我不起作用。

      我必须使用的检查 ssh-agent 是否正在运行的测试是:

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

      我正在启动 ssh-agent:

      exec ssh-agent bash
      

      否则不会设置SSH_AGENT_PID

      以下似乎适用于 Ubuntu 14.04 和 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
      

      【讨论】:

        【解决方案7】:

        我注意到拥有一个正在运行的代理是不够的,因为有时,SSH_AUTH_SOCK 变量被设置或指向一个不再存在的套接字文件。

        因此,要连接到您机器上已经运行的ssh-agent,您可以这样做:

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

        【讨论】:

        • 这是一个巧妙而巧妙的技巧,它解决了将代理 PID 与现有套接字配对的问题!最佳答案在这里。
        【解决方案8】:
        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
        

        然后你可以ssh-add xxxx一次,每次登录都可以使用ssh-agent。

        【讨论】:

        • @Wang-Zhang Nice ssh-agent 包装器。我喜欢它:+1:
        【解决方案9】:

        您可以将第 1 行修改为:

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

        然后在脚本的最后你可以这样做:

        kill -9 $PID_SSH_AGENT
        

        【讨论】:

        • 首先,$varname 引用了一个变量,不能这样设置。其次,如果eval ssh-agent 已经设置了 $SSH_AGENT_PID,为什么还要这样做?
        • 对不起,不知道它设置了那个变量。是的,$ 不应该在那里。谢谢。
        【解决方案10】:

        感谢这里的所有答案。多年来,我曾多次使用此线程来调整我的方法。想要分享我当前在 Linux 和 OSX 上适用的 ssh-agent.sh 检查器/启动器脚本。

        以下块是我的$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
        

        我从我的.bashrc 使用:

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

        希望这可以帮助其他人快速起床。

        如果您想和我一起破解/改进它,请创建一个公共要点:https://gist.github.com/dayne/a97a258b487ed4d5e9777b61917f0a72

        【讨论】:

          【解决方案11】:

          我创建了这个 bash 函数来计算并返回正在运行的 ssh-agent 进程的数量...它使用 procfs 搜索 ssh-agent 进程,而不是使用 $ ps -p $SSH_AGENT_PID:cmd 或 $SSH_AUTH_SOCK:var ...(这些ENV-var. 仍然可以在 ssh-agent 的进程已被杀死时使用旧值设置:如果 $ ssh-agent -k$ $(ssh-agent -k) 而不是 $ 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[@]}
          }
          

          ..然后如果有很多 ssh-agent 进程在运行,你可以通过这个列表获得他们的 PID..."${agent_list[@]}"

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-10-29
            • 1970-01-01
            相关资源
            最近更新 更多