如何用su -c在单一会话中执行ssh-agent与ssh-add多命令?
解决方案
问题核心在于:ssh-agent启动后会生成仅当前shell有效的环境变量(SSH_AUTH_SOCK、SSH_AGENT_PID),必须让ssh-add和eval $(ssh-agent -s)在同一个目标用户的shell会话里执行,同时要避免当前shell提前解析命令中的变量和子命令。
正确写法示例
方法1:转义子命令的$符号,保留变量展开
folder=/home/q12 username=q12 su "$username" -c "eval \$(ssh-agent -s); ssh-add $folder/.ssh/id_rsa"
\$(ssh-agent -s)中的反斜杠会阻止当前shell解析这个子命令,让切换到目标用户后再执行ssh-agent,生成属于目标用户的代理环境。$folder和$username会被当前shell提前展开,正确传递路径和用户名。
方法2:单引号+双引号混合包裹
folder=/home/q12 username=q12 su "$username" -c 'eval $(ssh-agent -s); ssh-add '"$folder"'/.ssh/id_rsa'
- 单引号包裹的部分会原封不动传给目标用户的shell,确保
ssh-agent在目标用户会话启动。 "$folder"用双引号包裹,让当前shell正确展开变量后拼接进命令。
方法3:使用Here-Doc(适合复杂命令场景)
folder=/home/q12 username=q12 su "$username" <<EOF eval \$(ssh-agent -s) ssh-add "$folder"/.ssh/id_rsa EOF
- Here-Doc会将内容作为目标用户shell的输入,逐行执行命令,语法更清晰,适合多命令组合。
为什么之前的写法失败
- 第一种写法中,
$(ssh-agent -s)是当前用户执行的,生成的代理socket属于当前用户,目标用户的ssh-add无权限访问;且{}后的ssh-add是在当前shell执行的,没有目标用户的代理环境变量。 - 后面几种写法中,
su执行完后ssh-add回到当前用户shell,没有目标用户的代理环境变量,因此无法连接代理。
内容的提问来源于stack exchange,提问作者SnackK0515
相关产品推荐
相关产品推荐

