Bash跨站点应用故障转移脚本:远程执行结果获取及语法问题
跨站点Pacemaker应用故障转移脚本问题
我正在编写Bash脚本实现跨站点应用故障转移,应用由Pacemaker管控。计划编写函数接收变量,实现应用在一个站点停止、另一个站点启动,但通过SSH连接远程机器后,无法获取PCS应用状态的grep/awk命令结果。
遇到的问题:
- 本地用户有管理员设置的横幅,将SSH命令输出重定向到
/dev/null 2>&1,-q参数无效,这是否会阻止结果返回? - 使用
awk '{print \\\$4}'时,出现"backslash not last character on line"错误; - 尝试用
result=$(sudo pcs status | grep nds_$resource)规避,却出现sudo密码错误; - 已尝试
>/dev/tty和>$(tty); - 移除SSH的输出抑制(删除
/dev/null 2>&1),函数调用时将输出存入变量,同时从sudo pcs status中移除awk,执行以下代码正常:
但添加result=$(pcs_call "$site1" "1" "2" "disable" "pmr") echo $result | grep systemd| awk '{print \\$4}'后得到的是横幅中的第四个单词。
测试用精简函数代码:
site1=lon site2=ire function pcs_call() { site=$1 serverA=$2 serverB=$3 activity=$4 resource=$5 ssh -tt ${site}servername0${serverA} <<SSH > /dev/null 2>&1 sudo pcs resource ${activity} proc_${resource} sleep 10 sudo pcs status | grep proc_$resource | awk '{print \\$4}' | tee $output exit SSH echo $output } echo ==================================================================================== echo Shutting Down PMR in $site1 pcs_call "$site1" "1" "2" "disable" "pmr"
问题解决与脚本修正
1. SSH输出重定向导致结果丢失
把SSH的标准输出和错误全重定向到/dev/null会直接丢弃远程命令的所有输出,包括pcs status的结果,自然拿不到数据。要保留结果,不能全丢输出,而是要过滤横幅:
- 用
sed过滤横幅(假设横幅以空行结束):ssh ${site}servername0${serverA} "sudo pcs status" | sed '1,/^$/d' - 非必要情况下去掉
-tt参数(强制伪终端会导致输出混乱),或用-T禁用伪终端避免横幅干扰。
2. awk变量转义错误
在Here Document(<<SSH)中,本地Shell会解析变量和转义字符:
- 如果不需要在远程命令中使用本地变量,用
<<'SSH'(单引号包裹分界符)禁用本地解析,远程awk的$4无需转义:ssh ${site}servername0${serverA} <<'SSH' sudo pcs status | grep proc_resource | awk '{print $4}' SSH - 如果需要使用本地变量(比如
$resource),不能用单引号包裹分界符,此时awk的$4只需转义一次(\$4)即可,不需要三次转义。
3. sudo密码问题
远程执行sudo需要交互式输入密码,脚本中无处理导致错误,解决方式二选一:
- 推荐:给远程用户配置免密sudo权限,编辑远程机器的
/etc/sudoers(用visudo避免语法错误),添加规则:username ALL=(ALL) NOPASSWD: /usr/sbin/pcs - 非生产环境可临时用
sshpass传递密码(不安全):sshpass -p 'yourpassword' ssh ${site}servername0${serverA} "sudo pcs ..."
4. 横幅混入输出导致awk取错内容
移除SSH输出抑制后,横幅会混入结果,可通过以下方式过滤:
- 远程端直接跳过横幅行(假设横幅共3行):
ssh ${site}servername0${serverA} "sudo pcs status | tail -n +4 | grep proc_$resource | awk '{print \$4}'" - 本地端过滤(只保留含目标资源的行):
raw_result=$(ssh ${site}servername0${serverA} "sudo pcs status") clean_result=$(echo "$raw_result" | grep proc_$resource | awk '{print $4}')
修正后的完整函数
site1=lon site2=ire function pcs_call() { local site=$1 local serverA=$2 local activity=$3 local resource=$4 # 使用本地变量时,Here Document不包裹单引号,awk的$4转义一次 local output=$(ssh ${site}servername0${serverA} <<SSH sudo pcs resource ${activity} proc_${resource} sleep 10 # 假设横幅前2行,根据实际情况调整行数 sudo pcs status | tail -n +3 | grep proc_${resource} | awk '{print \$4}' SSH ) echo "$output" } echo "====================================================================" echo "Shutting Down PMR in $site1" pcs_call "$site1" "1" "disable" "pmr"
内容的提问来源于stack exchange,提问作者Red_badger
相关产品推荐
相关产品推荐

