【bash】2、手把手实现一个 bash shell:多个机器批量执行 shell 命令,支持 ip 补全

文章目录

  • 一、需求:多台机器批量远程执行 shell 命令
    • 1.1 业务需求拆解为脚本需求
    • 1.2 帮助函数:使用说明文档
    • 1.3 main 函数框架
  • 二、功能:单机 sshp 执行
    • 2.1 fullip 函数:实现 ip 补全
      • 2.1.1 参数说明
      • 2.1.2 定义全局变量
      • 2.1.3 实现:正则匹配、if 分支
      • 2.1.4 测试
    • 2.2 sshp 函数
      • 2.2.1 参数说明
      • 2.2.2 定义全局变量
      • 2.2.3 实现:利用 sshpass 传参
      • 2.2.4 测试
  • 三、功能:多机批量 batch_sshp 执行
    • 3.1 batch_sshp 函数:多机 sshp 执行
      • 3.1.1 参数说明
      • 3.1.2 实现
        • 3.1.2.1 利用 awk 分隔一个参数
        • 3.1.2.2 利用 awk 分隔多个参数
        • 3.1.2.3 批量执行脚本
      • 3.1.3 测试、使用示例
        • 3.1.3.1 执行 ls 查看目录
        • 3.1.3.2 执行 df 查看磁盘占用率
      • 3.1.4 完整脚本

一、需求:多台机器批量远程执行 shell 命令

这个脚本可以执行任何命令,用途是广泛的,例如执行 ls 查看目录,或执行 df 查看磁盘占用率

1.1 业务需求拆解为脚本需求

首先可以写 shell 批量获取各机器的磁盘占用率,通过在各机器执行 df -h | head 实现

希望的使用示例为:

mgr.sh 2.99 2.100 df -h | head

1.2 帮助函数:使用说明文档

首先写 print_help()

 # print_helpprint_help() {cat << EOF$0ssh IP1 IP2 ... [cmd]            -- ssh 连接 IP,执行 cmdfullip SUFFIX_IP                 -- 获取完整的 IP 地址EOFexit}

1.3 main 函数框架

然后写 main 函数

# maincase $1 inssh)shiftsshp "$@";;fullip)shiftfullip "$@";;*)print_help;;esac

二、功能:单机 sshp 执行

2.1 fullip 函数:实现 ip 补全

2.1.1 参数说明

然后实现 fullip 函数,先写改函数的参数说明:

 # fullip# 根据 ip 后缀,补全完整的 ip 地址# 参数$1 为 ip 地址的后缀fullip() {}

2.1.2 定义全局变量

然后在文件开头,定义全局变量 ip_prefix=192.168

# 全局信息
# ip 前缀
PRE_IP=192.168

2.1.3 实现:正则匹配、if 分支

然后实现 fullip 函数

 # 全局信息# ip 前缀PRE_IP=192.168# fullip# 根据 ip 后缀,补全完整的 ip 地址# 参数$1 为 ip 地址的后缀fullip() {[ "x$1" == "x" ] && echo "Error: 请输入 IP 后缀" && exit 10# 已经是完整的 ip 地址if [[ $1 =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; thenecho $1return# 只有 2 位的ip 后缀elif[[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}$ ]]; then# 补全完整的 ip 地址echo $PRE_IP.$1returnelseecho -e "Error: 请输入正确的 IP 后缀"exit 101fi}

2.1.4 测试

然后测试脚本, 一切正常:

# 先执行脚本,不输入参数
./mgr.sh
./mgr.shssh IP1 IP2 ... [cmd]            -- ssh 连接 IP,执行 cmdfullip SUFFIX_IP                 -- 获取完整的 IP 地址# 再执行 fullip,输入全量 ip
./mgr.sh fullip 192.168.2.1
192.168.2.1# 再执行 fullip,输入ip 后缀
./mgr.sh fullip 2.99
192.168.2.99

2.2 sshp 函数

然后,写 sshp 函数,通过 sshpass 远程执行命令

2.2.1 参数说明

首先写参数说明

# sshp: 通过 sshpass 执行远程命令
# $1 是补全的 ip
# ssh 协议的用户名和密码,是写死的全局变量
# $@ 是ssh 需执行的 cmd

然后补全函数声明, 其实 shell 函数都是形如 f() {} 的

# sshp: 通过 sshpass 执行远程命令
# $参数 $1 为 ip 地址, 和 shell 的 $1 是一样的,可能是完整的 ip,也可能是 ip 的后缀
# ssh 协议的用户名和密码,是写死的全局变量
# $@ 是ssh 需执行的 cmd
sshp() {}

2.2.2 定义全局变量

然后,定义全局变量,即 ssh 的用户名和密码。

这取决于需求,如果所操作的机器的用户名和密码都是相同的,则可以写死为全局变量。否则可以在脚本参数中输入。

USER=ubuntu
PASSWORD=ubuntu

2.2.3 实现:利用 sshpass 传参

 sshp() {sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no "$USER"@$1 "$@"}

注意,sshpass 是 main 函数的入口,所以其输入的参数 $1 就是整个 shell 的 参数 $1。

而 $1 虽然是 ip,但可能是完整的 ip 或者 仅 ip 后缀。

所以需要在 sshp() 做两步工作:

  1. 内调用 fullip() 实现 ip 的补全
  2. 将补全的 ip 传参给 sshpass

因此改写为如下:

 # sshp# 利用 sshpass 连接到指定的 ip 地址,并执行命令# 参数 $1 为 ip 地址, 和 shell 的 $1 是一样的,可能是完整的 ip,也可能是 ip 的后#缀sshp() {local remote=$(fullip $1)echo -e "remote is: $remote"# 注意解析完 $1 后,则需要 shift,以便解析后续参数shiftsshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no "$USER"@${remote} "$@"}

2.2.4 测试

# 打印帮助信息
$ ./mgr.sh
./mgr.shssh IP1 IP2 ... [cmd]            -- ssh 连接 IP,执行 cmdfullip SUFFIX_IP                 -- 获取完整的 IP 地址# 远程 ssh 执行一个命令
$ ./mgr.sh ssh 2.99 ls
remote is: 192.168.299
a.txt
b.json

三、功能:多机批量 batch_sshp 执行

3.1 batch_sshp 函数:多机 sshp 执行

需求拆解:

多机 sshp 批量执行,因为要多个机器执行,所以需要填多个 ip,例如以空格分隔

因此 ips 和 cmd 之间要有明确的分隔符,例如 cmd

3.1.1 参数说明

./mgr.sh batch_ssh < ip | ip_suffix …> cmd

# 首先解析 ip 列表
# 其次解析 shell-cmds(通过 cmd 关键字)
bahch_ssh() {}

思路:利用 awk 分隔参数

首先,main 解析 $1,如果是 “batch_ssh”,则执行 batch_ssh() 并将参数 shift

然后,用 awk 按 cmd 关键字,拆分参数为 ips 和 shell-cmd,存储到两个 local 变量里

其次,for ip in ips 遍历得到 ip 列表,每次循环都执行一次 sshp 函数

而,shell-cmd 变量则无需解析,直接在 sshp 函数使用即可

所以,完善的函数声明如下:

# batch_ssh
# 对多个机器,批量执行命令
# 根据 "cmd" 关键字,将命令分成两部分,前一部分是 ips 地址数组,后一部分是命令
# 用 for 遍历 ips 数组,对每个 ip 执行命令
batch_ssh() {}

3.1.2 实现

3.1.2.1 利用 awk 分隔一个参数
# batch_ssh
# 对多个机器,批量执行命令
# 根据 "cmd" 关键字,将命令分成两部分,前一部分是 ips 地址数组,后一部分是命令
# 用 for 遍历 ips 数组,对每个 ip 执行命令batch_ssh() {local ips=$(echo "$@" | awk -F 'cmd' '{print $1}')echo -e "ips: ${ips}"echo -e "ips: ${ips[@]}"}

测试:

./mgr.sh batch_ssh 2.99 2.100
ips: 2.99 2.100
ips: 2.99 2.100
3.1.2.2 利用 awk 分隔多个参数
 batch_ssh() {local ips=$(echo "$@" | awk -F 'cmd' '{print $1}')local shellcmds=$(echo "$@" | awk -F 'cmd' '{print $2}')echo -e "ips: ${ips}"echo -e "shellcmds: ${shellcmds}"}

测试:

./mgr.sh batch_ssh 2.99 2.100 cmd ls -lrt
ips: 2.99 2.100
shellcmds:  ls -lrt
3.1.2.3 批量执行脚本
 batch_ssh() {local ips=$(echo "$@" | awk -F 'cmd' '{print $1}')local shellcmd=$(echo "$@" | awk -F 'cmd' '{print $2}')echo -e "ips: ${ips}"echo -e "shellcmds: ${shellcmd}"for ip in ${ips}; dolocal remote=$(fullip $ip)echo -e "\n-----开始执行: $remote-----"sshp $remote $shellcmddoneecho -e "执行完毕"}

并补全帮助信息

 # print_helpprint_help() {cat << EOF$0ssh < IP | IPSUFFIX ...> <shellcmd>            -- ssh 连接 IP,执行 cmdbatch_ssh < IP | IPSUFFIX ...> cmd <shellcmd>  -- 对多个机器,批量执行命令fullip SUFFIX_IP                               -- 获取完整的 IP 地址EOFexit}

3.1.3 测试、使用示例

这个脚本可以执行任何命令,用途是广泛的

3.1.3.1 执行 ls 查看目录
./mgr.sh batch_ssh 2.99 2.100 cmd ls -lrt
ips: 2.99 2.100
shellcmds:  ls -lrt-----开始执行: 192.168.2.99-----
remote is: 192.168.2.99
a.txt
b.json-----开始执行: 192.168.2.100-----
remote is: 192.168.2.100
c.json
d.ini执行完毕
3.1.3.2 执行 df 查看磁盘占用率
mgr.sh batch_ssh 2.99 2.100 cmd df -h
ips: 2.99 2.100
shellcmds:  df -h-----开始执行: 192.168.2.99-----
remote is: 192.168.2.99
Filesystem      Size  Used Avail Use% Mounted on
udev             16G     0   16G   0% /dev
tmpfs           3.2G  1.8M  3.2G   1% /run
/dev/vda2        49G   25G   22G  54% /-----开始执行: 192.168.2.100-----
remote is: 192.168.2.100
Filesystem      Size  Used Avail Use% Mounted on
udev             48G     0   48G   0% /dev
tmpfs           9.5G  899M  8.6G  10% /run
/dev/sda1       117G   68G   44G  61% /执行完毕

3.1.4 完整脚本

#!/bin/bash# 全局信息
# ip 前缀
PRE_IP=192.168
USER=ubuntu
PASSWORD=ubuntu# fullip
# 根据 ip 后缀,补全完整的 ip 地址
# 参数$1 为 ip 地址的后缀
fullip() {[ "x$1" == "x" ] && echo "Error: 请输入 IP 后缀" && exit 10# 已经是完整的 ip 地址if [[ $1 =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; thenecho $1return# 只有 2 位的ip 后缀elif[[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}$ ]]; then# 补全完整的 ip 地址echo ${PRE_IP}.$1returnelseecho -e "Error: 请输入正确的 IP 后缀"exit 101fi
}# sshp
# 利用 sshpass 连接到指定的 ip 地址,并执行命令
# 参数 $1 为 ip 地址, 和 shell 的 $1 是一样的,可能是完整的 ip,也可能是 ip 的后#缀
sshp() {local remote=$(fullip $1)echo -e "remote is: $remote"shiftsshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no "$USER"@${remote} "$@"
}# batch_ssh
# 对多个机器,批量执行命令
# 根据 "cmd" 关键字,将命令分成两部分,前一部分是 ips 地址数组,后一部分是命令
# 用 for 遍历 ips 数组,对每个 ip 执行命令
batch_ssh() {local ips=$(echo "$@" | awk -F 'cmd' '{print $1}')local shellcmd=$(echo "$@" | awk -F 'cmd' '{print $2}')echo -e "ips: ${ips}"echo -e "shellcmds: ${shellcmd}"for ip in ${ips}; dolocal remote=$(fullip $ip)echo -e "\n-----开始执行: $remote-----"sshp $remote $shellcmddoneecho -e "\n执行完毕"
}# print_help
print_help() {
cat << EOF
$0ssh < IP | IPSUFFIX ...> <shellcmd>            -- ssh 连接 IP,执行 cmdbatch_ssh < IP | IPSUFFIX ...> cmd <shellcmd>  -- 对多个机器,批量执行命令fullip SUFFIX_IP                               -- 获取完整的 IP 地址
EOF
exit
}# main
case $1 inssh)shiftsshp "$@";;batch_ssh)shiftbatch_ssh "$@";;fullip)shiftfullip "$@";;*)print_help;;
esac

执行效果

$ ./mgr.sh
./mgr.shssh < IP | IPSUFFIX ...> <shellcmd>            -- ssh 连接 IP,执行 cmdbatch_ssh < IP | IPSUFFIX ...> cmd <shellcmd>  -- 对多个机器,批量执行命令fullip SUFFIX_IP

环境配置:通常会在 vim 写 shell 脚本,可以用开源的 vimrc 配置 https://github.com/amix/vimrc 替我们解决高亮等美观问题,提升效率

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/501038.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Doccano 修复 spacy.gold 的bug

引言 最初只是想把Doccano标注的数据集转换成BIO(类似conll2003数据集)的标注格式&#xff1b; 摘要 可先阅读一下教程&#xff1a;【已解决】关于如何将Doccano标注的文本转换成NER模型可以直接处理的CoNLL 2003格式 装包:pip install doccano-transformer 报错信息 运行…

基于springboot+vue的中药实验管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

SpringBoot源码解读与原理分析(三十八)SpringBoot整合WebFlux(一)WebFlux的自动装配

文章目录 前言第13章 SpringBoot整合WebFlux13.1 响应式编程与Reactor13.1.1 命令式与响应式13.1.2 异步非阻塞13.1.3 观察者模式13.1.4 响应性13.1.5 响应式流13.1.6 背压13.1.7 Reactor13.1.7.1 Publisher13.1.7.2 Subscriber13.1.7.3 Subscription13.1.7.4 Processor13.1.7.…

【机器学习实战1】泰坦尼克号:灾难中的机器学习(一)数据预处理

&#x1f338;博主主页&#xff1a;釉色清风&#x1f338;文章专栏&#xff1a;机器学习实战&#x1f338;今日语录&#xff1a;不要一直责怪过去的自己&#xff0c;她曾经站在雾里也很迷茫。 &#x1f33c;实战项目简介 本次项目是kaggle上的一个入门比赛 &#xff1a;Titani…

【01】openEuler 源码安装 PostgreSQL

openEuler 源码安装 PostgreSQL 部署环境说明Shell 前端软件包管理器基础概念YUM 简介DNF 简介 源码安装 PostgreSQL环境变量&#xff08;env&#xff09;设置临时环境变量设置永久环境变量设置 初始化数据库&#xff08;initdb&#xff09; 数据库基本操作数据库基本配置&…

稀疏图带负边的全源最短路Johnson算法

BellmanFord算法 Johnson算法解决的问题 带负权的稀疏图的全源最短路 算法流程 重新设置的每条边的权重都大于或等于0&#xff0c;跑完Djikstra后得到的全源最短路&#xff0c;记得要还原&#xff0c;即&#xff1a;f(u,v) d(u,v) - h[u] h[v] 例题

提升智能客服机器人的语义理解能力:理解用户的语义和意图

智能客服机器人的发展已经成为现代服务业的一大亮点。它们不仅能够提供724小时不间断的服务&#xff0c;而且能够处理大量的用户请求&#xff0c;大大提高了服务效率。然而&#xff0c;尽管智能客服机器人的技术已经取得了显著的进步&#xff0c;但其语义理解能力仍有待提高。为…

StarRocks实战——vivo基于 StarRocks 构建实时大数据平台

目录 前言 一、数据挑战 1.1 时效性挑战&#xff0c;业务分析决策需加速 1.2 访问量挑战&#xff0c;性能与稳定性亟待提高&#xff0c;支撑业务稳定运行 1.3 计算场景挑战&#xff0c;难以满足业务复杂查询需求 1.4. 运维挑战&#xff0c;用户查询体验需优化 二、OLA…

Flink——芒果TV的实时数仓建设实践

目录 一、芒果TV实时数仓建设历程 1.1 阶段一&#xff1a;Storm/Flink JavaSpark SQL 1.2 阶段二&#xff1a;Flink SQLSpark SQL 1.3 阶段三&#xff1a;Flink SQLStarRocks 二、自研Flink实时计算调度平台介绍 2.1 现有痛点 2.2 平台架构设计 三、Flink SQL实时数仓分…

utniy urp shinyssrr插件使用

文章目录 前言步骤1首先在URP的配置文件里添加SSR后处理2 修改RenderingPath为延迟渲染3 启用深度纹理4 为物体添加脚本 插件下载 前言 用来实现屏幕空间反射效果 unity 版本为2021.3.8LTS&#xff0c;低版本的untiy URP的参数设置位置z可能会不同 步骤 1首先在URP的配置文件…

经销商文件分发 怎样兼顾安全和效率?

经销商文件分发是指将文件、资料、产品信息等从制造商或经销商传递给经销商的过程。这一过程对于确保经销商能够获取最新的产品信息、销售策略、市场活动资料等至关重要。 想要管理众多经销商合作伙伴之间的文件传输并提高效率&#xff0c;可以采取以下措施&#xff1a; 1、建…

gpt批量原创文章生成器,不限制内容的生成器

在当今的数字化时代&#xff0c;内容创作是网站持续发展的重要组成部分。然而&#xff0c;对于拥有大量内容需求的网站来说&#xff0c;手动创作文章可能会耗费大量时间和精力。为了解决这一问题&#xff0c;许多GPT&#xff08;生成式预训练模型&#xff09;文章生成软件应运而…