直接的解决方法是将命令指定为ssh 的参数——然后连接将建立,命令将运行,连接将关闭
#!/bin/bash
user=pepe
host=server
pass=`cat /tmp/password.txt`
COMMAND=df
PASSWORD=$pass expect -c "
spawn ssh $user@$host $COMMAND
expect \"*assword*\"
send \$env(PASSWORD)\r
expect eof
"
有几点需要注意:
-
expect eof 将优雅地等待生成的命令退出
- 我已经转义了内部双引号。
下一步是整理引用/转义。在 shell 脚本中嵌入另一种语言的代码时,使用带引号的 heredoc 是避免引用地狱的最佳方法。这意味着所有的shell变量都需要通过环境传递给expect
#!/bin/bash
export user=pepe
export host=server
export pass=`cat /tmp/password.txt`
export cmd=df
expect << 'END_EXPECT'
spawn ssh $env(user)@$env(host) $env(cmd)
expect "*assword*"
send $env(pass)\r
expect eof
END_EXPECT
我要做的最后一件事是减少密码的暴露。 Expect 建立在tcl 语言之上,完全可以读取文件:
#!/bin/bash
export user=pepe
export host=server
export pass=`cat /tmp/password.txt`
export cmd=df
expect << 'END_EXPECT'
set fh [open /tmp/password.txt]
gets $fh pass
close $fh
spawn ssh $env(user)@$env(host) $env(cmd)
expect "*assword*"
send $pass\r
expect eof
END_EXPECT
并确保该密码文件的权限尽可能严格:
mv /tmp/password.txt ~/.local/share/pass.txt
chmod 0400 ~/.local/share/pass.txt