如何通过SSH执行本地Shell函数及优化EC2资源监控脚本
SSH远程执行本地函数的解决方法
报错原因
你遇到的模糊重定向错误及函数执行失败有两个核心原因:
- 仅传递了本地变量声明,未将
func_mail2_alert函数的定义同步到远程SSH会话,远程环境无法识别该函数- 你在本地生成的
TMPFILE路径仅存在于执行脚本的管控机器上,远程EC2实例没有对应路径,函数执行写入文件时触发重定向错误
正确实现方案
你可以通过declare -f将本地函数序列化后传递到远程会话,同时建议调整逻辑:资源收集在远程执行,结果返回本地后统一发邮件,无需每台EC2配置邮件服务。
正确的SSH执行代码示例如下:
# 首先调整函数为输出监控数据到标准输出,无需远程写临时文件 func_collect_remote_metrics() { uptime echo -e "\n\n" free -m echo -e "\n\n" echo -e "TOP - 1" top -d1 -n1 -b -c -i | head -25 echo -e "\n\n" echo -e "TOP - 2" top -d1 -n1 -b -c -i | head -25 echo -e "\n\n" echo -e "PS_MEM\nPrivate + Shared = RAM used Program\n" ps_mem | tail -25 } # 一次SSH会话完成CPU校验+监控数据采集 SSH_OUTPUT=$(ssh -i "${SSH_IDENTITY}" ec2-user@"${IP_PUBLIC}" "\ $(declare -f func_collect_remote_metrics); \ CPU_LOAD=\$(cat /proc/loadavg | cut -d ' ' -f2 | cut -d . -f1); if [[ \${CPU_LOAD} -ge 1 ]]; then # 阈值可根据实例核心数调整 func_collect_remote_metrics fi") # 本地判断是否触发告警,生成邮件 if [[ -n "${SSH_OUTPUT}" ]]; then TMPFILE=$(mktemp /tmp/ec2-alert.XXXXXX) echo "${SSH_OUTPUT}" > "${TMPFILE}" # 此处复用你原有的邮件发送逻辑即可 rm -f "${TMPFILE}" fi
脚本优化建议
- 减少重复AWS API调用:你当前对同一实例发起了3次aws cli请求,可合并为1次调用一次性获取实例状态、公网IP、私网IP,降低API限流风险和执行耗时
- 变量统一加双引号:所有变量引用如
${instances[@]}、${SSH_IDENTITY}都要包裹双引号,避免路径/值包含空格时脚本执行异常 - 合并SSH连接:原脚本对同一实例先后发起3次SSH连接(连通性测试、取CPU负载、执行函数),可合并为1次SSH会话完成所有操作,降低连接开销
- 修正CPU告警阈值:原代码的
[[ "${SSH_CPU_USAGE}" -ge 0 ]]判断条件会导致只要实例运行就触发告警,完全不符合需求,建议根据实例CPU核心数设置合理阈值,比如单核实例设为1、4核实例设为3 - 清理临时文件:原脚本生成的
TMPFILE没有删除逻辑,长期运行会堆积垃圾文件,建议邮件发送完成后执行rm -f ${TMPFILE}清理 - 简化IP获取逻辑:无需用grep正则从jq输出中捞IP,可直接用jq输出原生IP值,比如公网IP可直接用
aws ec2 describe-instances --instance-ids "${ec2instances}" | jq -r '.Reservations[0].Instances[0].PublicIpAddress',准确度更高 - 增加错误处理:可在脚本开头加
set -euo pipefail开启严格模式,避免变量未定义、命令执行失败时脚本继续异常运行,同时补充SSH连接失败、AWS API调用失败的告警逻辑
内容的提问来源于stack exchange,提问作者pi314
相关产品推荐
相关产品推荐

