通过SSH执行含sudo命令的远程脚本时卡在首行无法执行后续命令的问题
卡顿的核心原因
sudo -s根本不是适合写到脚本里的提权命令,它的作用是打开一个可持续接收命令输入的交互式root shell,启动后不会自动退出,会一直停在等待用户输入的状态。- 脚本的执行逻辑是逐行运行:等上一个命令完全退出、把控制权还给脚本进程,才会执行下一行。第一行的
sudo -s启动交互式shell之后就卡在输入等待状态,后面写的sudo apt-get update、sudo apt-get upgrade根本没有机会被执行,整个脚本流程直接被堵死。 - 你在ssh命令里加的
-tt参数是强制为远程会话分配伪终端,本来是为了适配需要终端输入的场景,结果反而给这个交互式的sudo -s提供了正常的输入环境,让它更不会自动退出,直接彻底卡住。
对应解决方案
根据你的实际使用场景选择即可:
方案1:删掉错写的sudo -s行
最省事的调整就是去掉无意义的交互式shell启动命令,需要root权限的命令单独加sudo前缀,同时给apt命令加上-y参数,避免升级过程中卡在交互确认提示:
修改后的server.sh内容:
sudo apt-get update -y sudo apt-get upgrade -y
提醒:如果远程登录的账号没有配置sudo免密,这种非交互执行的场景还是会卡在密码输入环节,需要配合下面的免密配置使用。
方案2:给远程登录账号配置sudo免密
针对你用pem密钥登录的账号,在远程服务器上用visudo编辑sudoers配置(千万别直接手动修改sudoers文件,语法错误会导致sudo功能完全失效),给对应账号添加免密规则:
你的远程登录用户名 ALL=(ALL) NOPASSWD:ALL
配置完成后,脚本里的sudo命令不需要手动输入密码,不会卡在交互环节。
方案3:整个脚本直接以root权限运行
如果不想逐行给命令加sudo前缀,可以直接在ssh执行环节让整个脚本以root身份运行,server.sh里完全不需要写任何sudo命令:
- 修改后的server.sh(普通命令格式,无需提权前缀):
apt-get update -y apt-get upgrade -y
- 修改后的client.sh对应ssh执行行:
ssh -i "$key.pem" $dns "sudo bash /tmp/server.sh"
这种方式从根源上避开了交互式shell的使用坑点,执行效率也更高。
应急临时方法(不推荐长期使用)
如果临时不想配置免密,可以用sudo的-S参数让它从标准输入读取密码,把密码通过管道传入即可:
echo "你的sudo账号密码" | sudo -S apt-get update -y
这种方法会把密码明文存在脚本内容里,有信息泄露风险,仅适合临时测试场景使用。
内容的提问来源于stack exchange,提问作者xywz
相关产品推荐
相关产品推荐

