Python脚本无sudo时SSHFS挂载失效且无错误提示问题排查
无sudo时SSHFS挂载失效的原因及解决方法
问题描述
在WSL环境下,命令行执行sshfs -o allow_other root@192.168.122.131:/root /mnt/123可正常挂载CentOS 8服务器的目录,但通过Python脚本调用pexpect执行相同命令时,无错误提示但挂载未生效;添加sudo后脚本可正常挂载,但实际场景无法依赖sudo权限。
原因分析
1. allow_other选项的权限限制
非root用户使用allow_other选项时,默认需要满足以下条件之一,否则会静默失败:
- 当前用户属于
fuse用户组 - 系统已在
/etc/fuse.conf中开启user_allow_other配置
这种情况下,sshfs进程会直接退出,挂载失效,但可能返回码仍为0,导致脚本无法捕获错误。
2. sshfs前台运行导致进程被终止
sshfs默认以前台模式运行,当pexpect完成交互并关闭子进程时,sshfs进程会被终止,挂载点随即被卸载。而命令行执行时,sshfs保持前台运行,挂载点不会被卸载;使用sudo时,因会话环境差异,进程未被立即终止,挂载得以生效。
解决方法
修复allow_other权限问题
选择以下任一方式:
- 将用户加入fuse组:
执行后退出当前会话并重新登录,权限才会生效。sudo usermod -aG fuse $USER - 开启user_allow_other配置:
编辑/etc/fuse.conf,取消user_allow_other行的注释:
找到sudo nano /etc/fuse.conf#user_allow_other,删除开头的#,保存退出后无需重启即可生效。
让sshfs后台运行,避免进程被终止
修改脚本中的命令和pexpect逻辑,让sshfs后台运行,同时调整等待逻辑:
def sshfs(ip, user, password, path_fonte, path_montado, timeout=30, bg_run=False): import tempfile import pexpect fname = tempfile.mktemp() fout = open(fname, 'w') # 添加-f选项让sshfs后台运行 ssh_cmd = f"sshfs -o allow_other -f {user}@{ip}:{path_fonte} {path_montado}" print(ssh_cmd) child = pexpect.spawnu(ssh_cmd, timeout=timeout, encoding='utf-8') try: child.expect(['[pP]assword: ']) child.sendline(password) # 等待几秒确认挂载完成,避免提前终止进程 child.expect(pexpect.TIMEOUT, timeout=5) child.close(force=True) except pexpect.EOF: # 提前收到EOF说明挂载失败 child.close() fout.close() fin = open(fname, 'r') stdout = fin.read() fin.close() raise Exception(f"挂载失败: {stdout}") fout.close() fin = open(fname, 'r') stdout = fin.read() fin.close() return stdout if __name__ == '__main__': print(sshfs(ip="192.168.122.131", user="root", password="root", path_fonte="/root", path_montado="/mnt/123")) print(pexpect.runu("ls -l " + "/mnt/123"))
可选:使用SSH密钥认证简化流程
配置SSH密钥认证可避免密码交互的复杂性,同时提升安全性:
- 在WSL生成密钥对:
ssh-keygen -t ed25519 - 将公钥复制到CentOS服务器:
ssh-copy-id root@192.168.122.131 - 简化脚本,去掉密码交互逻辑:
ssh_cmd = f"sshfs -o allow_other -f {user}@{ip}:{path_fonte} {path_montado}" child = pexpect.spawnu(ssh_cmd, timeout=timeout, encoding='utf-8') # 无需密码交互,直接等待确认 child.expect(pexpect.TIMEOUT, timeout=5) child.close(force=True)
内容的提问来源于stack exchange,提问作者iml
相关产品推荐
相关产品推荐

