bash - 在shell脚本中使用expect时命令执行出错,而在纯shell中工作正常
问题描述
我尝试启动部署在单独服务器中的所有退出的 docker 容器,所以基本上我应该执行下面的基本命令
[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)
它像在纯 linux shell 中一样工作得很好,但是当我尝试使用期望“发送”“基本”命令时发生错误(如下所示)。(本地ip是241,远端是209)
[root@localhost start_shell_dir]# spawn ssh root@192.168.1.209
root@192.168.1.209's password:
Last login: Fri Oct 15 22:23:25 2021 from 192.168.1.241
[root@localhost ~]# invalid command name "0"
while executing
"0 -ne 0 "
invoked from within
"send "[ 0 -ne 0 ] && docker start ""
错误日志显示我已经登录远程机器,执行 docker 命令时出现问题。
评论区的Glenn jackman向我展示了tcl 的基本规则,然后我意识到在发送真正的命令之前,expect 会进行命令替换。我们可以从 execute 中看到bash -x script.sh
。
[root@localhost start_shell_dir]# bash -x startContainer.sh
+ read ip pass
+ read ip pass
+ /usr/bin/expect
[root@localhost start_shell_dir]# ++ docker ps -a
++ grep Exited
++ wc -l
++ docker ps -a
++ grep Exited
++ cut '-d ' -f1
spawn ssh root@192.168.1.209
root@192.168.1.209's password:
Last login: Fri Oct 15 22:37:56 2021 from 192.168.1.241
[root@localhost ~]# invalid command name "0"
while executing
"0 -ne 0 "
invoked from within
"send "[ 0 -ne 0 ] && docker start ""
无论如何,对我有用的最后一个命令是下面显示的命令(用大括号替换双引号并在 $() 之前用反斜杠将其保留为普通字符,而不是预先解析它)。
send {[ \$(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start \$(docker ps -a | grep Exited | cut -d' ' -f1)}
#!/bin/bash
# my original script with error
while read ip pass
do
{
/usr/bin/expect <<-END
spawn ssh root@$ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
expect "#"
send "[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)"
expect eof
END
}&
done<apps_ip.txt
解决方案
与 shell 一样,Tcl(和期望)允许使用双引号进行插值。Tcl 使用方括号进行命令替换(与 shell 使用的方式相同$(...)
)
使用花括号来保护该字符串的内容(类似于 shell 的单引号):
send {[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)}
#....^.............................................................................................................^
# and don't forget to hit Enter
send "\r"
有关 Tcl 的一些语法规则,请参见https://www.tcl-lang.org/man/tcl8.6/TclCmd/Tcl.htm。
推荐阅读
- angular - 由于事件冒泡顺序,不能`stopPropagation()`?
- javascript - 图标克隆元素在错误的位置
- c - 未加权图的 Dijkstra 算法
- javascript - 在 D3 径向树中自定义 SVG 文本
- javascript - Angular:页面标题服务仍然会更改导航
- excel - 在遍历命名范围时,如何在 VBA 中准确指定 for each 循环的顺序?
- python - 合并列表中相同元素的列表
- java - Java MigLayout illegal constraint 'dock'
- swift - 如何在私有 cocoapod 库中添加另一个私有 cocoapod 库?
- r - 在某些条件下根据另一个变量的最小值生成一个新变量