远程执行需交互输入的Bash脚本遇输入失效问题求助
解决远程SSH执行脚本时的终端交互问题
你的问题核心在于:当用ssh user@server 'bash -s' < $script_dir/script.sh这种方式传脚本到远程执行时,远程进程的标准输入被本地的脚本文件占用了,导致脚本里需要终端交互的命令(比如输入密码、读取用户输入)无法获取输入,直接失败或跳过。下面给你几个可行的解决方案:
方案1:强制SSH分配伪终端(最通用的交互方案)
SSH默认不会给非交互式会话分配伪终端,这就是远程脚本没法读取你本地终端输入的原因。加上-tt参数可以强制分配伪终端,让远程脚本和你的本地终端建立交互连接。
修改你的执行命令为:
ssh -tt user@server 'bash -s' < $script_dir/script.sh
-tt参数会强制分配伪终端,即使你的本地不是终端环境也能生效。这样脚本里的ssh-keygen、ssh-copy-id、read这些需要输入的命令,都能正常读取你在本地终端的输入了。
方案2:提前传递参数,避免交互
如果你的场景可以提前知道需要输入的内容,完全可以把参数通过环境变量或命令行传递给远程脚本,修改脚本直接使用这些预定义的值,彻底避免交互。
示例1:通过环境变量传递参数
执行命令时把变量传递过去:
# 提前定义需要的变量 barmanserver="my-barman-server" db_user="username" db_pass="mysecretpass" ssh_key_pass="mykeypass" # 远程执行脚本,同时传递变量 ssh user@server "barmanserver=$barmanserver db_user=$db_user db_pass=$db_pass ssh_key_pass=$ssh_key_pass bash -s" < $script_dir/script.sh
然后修改你的script.sh,替换交互式命令:
# 替换ssh-keygen,用预定义的密码 ssh-keygen -t rsa -N "$ssh_key_pass" # 替换ssh-copy-id,用sshpass自动输入密码(需要远程安装sshpass) sshpass -p "$postgres_pass" ssh-copy-id postgres@$sqlserver # 替换createuser,用PGPASSWORD环境变量传递密码 PGPASSWORD="$db_pass" createuser -s -P "$db_user" # 替换read,直接用环境变量 printf "Using barman server: $barmanserver\n"
示例2:用Here-doc传递脚本和参数
这种方式可以把脚本内容和参数一起传递,同时保留交互能力(如果需要):
ssh -tt user@server bash -s <<EOF # 提前获取本地输入 barmanserver="$(read -p "Enter barman server name: " name; echo $name)" db_pass="$(read -sp "Enter DB password: " pass; echo $pass)" # 这里放你的脚本内容 ssh-keygen -t rsa ssh-copy-id postgres@$sqlserver ssh postgres@$sqlserver -C true printf "Creating user in postgresql server...\n" PGPASSWORD="$db_pass" createuser -s -P username EOF
针对具体命令的优化建议
- ssh-keygen:如果不需要密码,直接加
-N ""参数生成无密码密钥;如果需要密码,用-N "$passphrase"提前指定。 - ssh-copy-id:如果需要自动输入目标服务器密码,可以用
sshpass工具(远程需要先安装sshpass),命令格式为sshpass -p "target_pass" ssh-copy-id postgres@$sqlserver。 - createuser:PostgreSQL允许用
PGPASSWORD环境变量传递密码,或者用--password参数(注意部分版本可能需要配合--encrypted),这样就能避免交互式输入。 - read命令:只要用了
-tt参数,read -s barmanserver就能正常读取本地终端的输入,不需要额外修改。
内容的提问来源于stack exchange,提问作者Eva Cheung
相关产品推荐
相关产品推荐

