Bash脚本实现user1后台SSH登录并以Root执行命令的问题排查与解决方案咨询
解决Bash脚本中无法让user1保持SSH登录的问题
首先,先梳理你脚本里的明显问题,再分析核心原因和对应的解决方案:
1. 脚本中的拼写错误
你的脚本里有个低级笔误:runuser -l user 1 -c 'systemctl --user list-units'这里的user 1多了空格,应该是user1。这个错误会直接导致这条命令执行失败,虽然不是who看不到登录的核心原因,但必须先修正。
2. 核心问题:SSH会话无TTY且易被进程组回收
当你在脚本后台执行runuser -l user1 -c 'ssh localhost' &时,存在两个致命问题:
- 缺少TTY终端:脚本运行在非交互式环境下,没有分配终端(TTY)。而SSH的交互式登录必须依赖TTY才能保持会话,单独执行命令时你是在终端里操作,所以有TTY支持,SSH能正常留存;但脚本后台运行时没有TTY,SSH启动后会立刻退出。
- 进程组信号终止:即使SSH侥幸启动,当runuser的父进程(脚本)继续运行或结束时,后台的SSH进程会因为属于同一个进程组,收到SIGHUP信号被强制终止,哪怕你用了
&后台运行。
3. 解决方案:强制分配TTY并隔离进程
要让user1的SSH会话稳定留存,需要给SSH强制分配TTY,同时让进程脱离脚本的进程组,避免被回收。下面是修正后的完整脚本:
#!/bin/bash set -euo pipefail # 启动持久化SSH会话:强制分配TTY,用nohup脱离脚本进程组 echo "[+] Starting persistent SSH session for user1" nohup runuser -l user1 -c 'ssh -t -t -q localhost 2>/dev/null' >/dev/null 2>&1 & # 延长等待时间,确保SSH会话完全建立 sleep 2 echo "[+] Running systemctl --user commands as root" # 修正拼写错误:user1而非user 1 runuser -l user1 -c 'systemctl --user list-units' # 如果你不需要长期保持登录,可以取消下面两行的注释来终止SSH会话 # echo "[+] Killing active ssh sessions" # pkill -u user1 ssh echo "[+] Done"
关键修改点说明
ssh -t -t:强制分配TTY,即使在非交互式环境下也能让SSH保持交互式登录状态,这样who命令才能识别到这个会话。nohup ... >/dev/null 2>&1 &:用nohup让SSH进程脱离脚本的控制终端,避免脚本结束时发送SIGHUP信号终止进程;同时重定向所有输出到/dev/null,避免生成冗余的nohup.out文件。- 延长等待时间:把
sleep 1改成sleep 2,给SSH足够的时间完成会话建立,避免后续的systemctl命令在会话未就绪时执行。
4. 验证方法
运行脚本后,执行who命令,你应该能看到类似user1 pts/0 2024-05-20 10:00 (:0)的条目,其中pts/0就是SSH会话分配的TTY。如果要确认进程,执行ps aux | grep user1 | grep ssh就能看到对应的SSH进程。
5. 额外注意事项
- 确保user1已经配置了本地SSH免密登录(比如
~user1/.ssh/authorized_keys中添加了自己的公钥),否则SSH会要求输入密码,脚本因无交互会直接失败。 - 如果你需要
who一直显示user1登录状态,就不要执行kill命令;如果只是测试用,完成操作后再终止会话即可。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

