如何通过Bash脚本在远程gnome-terminal中正确分配变量?
解决Expect中命令替换的变量解析错误问题
你的问题核心是多层引号嵌套下的命令替换解析冲突:Expect会把$()里的内容当成自身的变量来解析,而不是将这个命令替换交给远程主机的Shell执行。下面是具体的修复方案和替代思路:
修复后的脚本
#!/bin/bash string_list=( host1 host2 host3 host4 ) password="12345" for i in "${!string_list[@]}"; do host="${string_list[$i]}" osascript -e " tell application \"Terminal\" do script \"expect -c ' spawn ssh -L 9999:localhost:9999 $host expect \\\"password:\\\" send \\\"$password\\r\\\" expect \\\"\$\\\" send \\\"foldername=\\\$(find 25* 2>/dev/null | grep -E '^25' | grep -v 'cycle' | sort | tail -n 1 | sed 's/.$//')\\r\\\" expect \\\"\$\\\" send \\\"cd \\\$foldername/\\\${foldername}_01/logs && tail -f console.log\\r\\\" interact'\" end tell" done
关键修改说明
转义命令替换的
$符号:- 将
foldername=$(find...)改为foldername=\$(find...)(在AppleScript语境下需要写成\\\$,因为要经过三层转义:Bash → AppleScript → Expect) - 目的是让
$(find...)完整传递到远程主机的Shell,而不是被Expect当作变量解析。
- 将
转义
$foldername和${foldername}中的$:- 同样要把
$foldername改为\$foldername(AppleScript里写成\\\$foldername),确保远程Shell能正确读取这个变量,而不是被Expect提前解析。
- 同样要把
补全缺失的引号:
- 原脚本中
send "$password\r"的末尾少了一个\",修复后保证语法闭合。
- 原脚本中
替代方案(更简洁)
如果不想纠结多层转义,可以把远程要执行的命令整合成一个字符串,用单引号包裹后传递给ssh,再结合Expect处理密码:
#!/bin/bash string_list=( host1 host2 host3 host4 ) password="12345" remote_cmd='foldername=$(find 25* 2>/dev/null | grep -E "^25" | grep -v "cycle" | sort | tail -n 1 | sed "s/.$//"); cd $foldername/${foldername}_01/logs && tail -f console.log' for host in "${string_list[@]}"; do osascript -e " tell application \"Terminal\" do script \"expect -c ' spawn ssh -L 9999:localhost:9999 $host \\\"$remote_cmd\\\" expect \\\"password:\\\" send \\\"$password\\r\\\" interact'\" end tell" done
这个方案把远程命令提前定义,减少嵌套转义的复杂度,更易维护。
内容的提问来源于stack exchange,提问作者Enub
相关产品推荐
相关产品推荐

