未整理
shell 中的 set -e 和 set +e的区别
区别:
set -e : 执行的时候如果出现了返回值为非零,整个脚本 就会立即退出
set +e: 执行的时候如果出现了返回值为非零将会继续执行下面的脚本
set -e 命令用法总结如下:
- 当命令的返回值为非零状态时,则立即退出脚本的执行。
- 作用范围只限于脚本执行的当前进行,不作用于其创建的子进程(https://blog.csdn.net/fc34235/article/details/76598448 )。
- 另外,当想根据命令执行的返回值,输出对应的log时,最好不要采用set -e选项,而是通过配合exit 命令来达到输出log并退出执行的目的。
二、Shell
shell是一个命令行解释器,它接收应用程序/用户命令,然后调用操作系统内核
它还是一个功能强大的编程语言,易编写,易调试,灵活性强
shell可以编写比较复杂的流程,形成脚本文件,它还有各种语法定义,形成各种复杂的流程控制
它的一个强大对手是python
2.1Shell的基本概念
2.1.1 Linux提供的shell解析器
centos使用的默认解析器
[atguigu@hadoop101 ~]$ cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
#查看默认解析器
echo $SHELL
#
#查看bin目录下的sh相关
ls -l /bin/ |grep sh
2.1.2 创建shell脚本
#先创建一个sh文件
touch hello.sh
#在文件内写入后为它增加可执行权限
chmod +x hello.sh
#执行文件
#在文件夹内执行
./hello.sh
#此处的.是一个命令
. hello.sh
#绝对路径执行
bash /root/scripts/hello.sh
source /root/scripts/hello.sh
2.2 变量
2.2.1 环境变量
变量即内存中存储的一块数据
常见的环境变量有
$HOME
$PWD
$SHELL
$USER
#查看当前所有的系统环境变量
env
#显示当前shell中所有变量(包含用户自定义和系统变量)
set
2.2.2 自定义变量
#声明为全局变量
export xxx
2.2.3 全局变量,只读变量和撤销变量
变量值的定义,默认都是字符串
只读变量:即常量
#定义只读变量
readonly b=5
#撤销变量,不能unset一个只读变量
unset a
如何让自己添加的脚本可以直接执行
自己添加的shell脚本需要在目录下./执行,或者在任何地方添加上绝对路径执行,如果想直接通过脚本名执行,有以下几种方式
1.将命令复制到/bin目录下,/bin目录下保存了系统可以执行的所有命令,但是这种方式不推荐,因为这个目录非常重要,不适合放很多自己的东西
2.我们当前找的系统命令的路径是可以配置的,echo $PATH 可以查看配置的环境路径,并且根目录下的/bin和/sbin都只是链接,都是指向/user/bin和/user/sbin,只要路径包含就可以使用
因此可以将自己的命令放入echo $PATH中的其他路径下面,例如/root/bin,也可以将命令所在的目录绝对路径,添加到环境变量内
2.2.4 特殊变量
主要用于处理脚本的特殊参数,对它进行捕获和处理
:
:
语法 | 功能 |
---|---|
$n | n为数字,$0代表脚本名称,$1-$9代表第一个到第九个参数,十以上的参数需要用大括号包含 |
$# | 用于获取所有输入参数的个数,常用于循环判断,判断参数的个数是否正确以及加强脚本的健壮性 |
$* | 代表命令行中所有的参数,把所有的参数看成一个整体 |
$@ | 代表命令行中所有的参数,把每个参数区分对待 |
$? | 显示最后一次执行的命令的返回状态 |
#在shell脚本中定义特殊变量
echo "hello $1"
#执行脚本,输入参数,会显示hello xiaoming
./hello.sh xiaoming
#如果不想让$生效,可以在脚本中用''定义,以下就不会生效,被认为是字符串
'=================$1======================'
2.3 运算符
2.3.1 基本语法
linux有内置的运算如下,但是太底层,不方便使用
#expr可以进行运行,但运算中间必须加空格,相当于把参数传进去
expr 1 + 2
# *在linux有特殊含义,必须转义之后才能当乘号使用
expr 6 \* 2
shell定义了简化的运算符,规则如下
$((表达式)) 或 $[表达式]
#通过运算符为变量赋值
a=$[6+8]
s=$[(2+3)*3]
#计算两数之和的脚本
vim add.sh
#脚本中的内容
sum=$[$1 + $2]
sum=$sum
#赋予权限
chmod +x add.sh
#执行,即会输出
./add.sh 34 43
2.4 条件判断
常用判断条件 | 解释 |
---|---|
-eq | 等于(equal) |
-ne | 不等于(not equal) |
-lt | 小于(less than) |
-le | 小于等于(less equal) |
-gt | 大于(greater than) |
-ge | 大于等于(greater equal) |
= | 判断相等 |
!= | 判断不等 |
-r | 有读的权限 |
-w | 有写的权限 |
-x | 有执行权限 |
-e | 文件存在 |
-f | 文件存在并且是一个常规文件 |
-d | 文件存在并且是一个目录 |
#定义一个变量
a=hello
#test进行条件判断测试
test $a = hello
#返回上一次的结果,即测试结果,结果是真返回0,结果是假返回1
echo $?
#常用的是直接用[ ]进行判断,两边一定要加空格
#并且=号两边要加空格,不然会被识别成一个值
[ $a = hello ]
#判断不相等
[ $a != hello ]
#判断目录中的文件是否存在
[ -e /home/atguigu/cls.txt ]
echo $?
#三元运算符表达式,条件为真,则返回ok,否则notOK
[ atguigu ] && echo OK || echo notOK
2.5 流程判断
if判断
单分支
if [ 条件 ];then
程序
fi
#或者
if [ 条件 ]
then
程序
fi
#-a 代表逻辑与的关系,-o代表逻辑或的关系
if [ $a -gt 18 -a $a -lt 35 ];then echo OK; fi
多分支
if [ $1 -eq 1 ]
then
echo "输出 1"
elif [ $1 -eq 2 ]
then
echo "输出2"
else
echo "输出其他"
fi
case
case 行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束
双分号“;;”表示命令序列结束,相当于 java 中的 break
最后的“*)”表示默认模式,相当于 java 中的 default
case $1 in
"1")
echo "输出1"
;;
"2")
echo "输出2"
;;
*)
echo "输出其他"
;;
esac
for循环
#从1加到100
sum=0
for((i=0;i<=100;i++))
do
sum=$[$sum+$i]
done
echo $sum
#打印数字,会循环输出三次
for i in cls mly wls
do
echo "ban zhang love $i"
done
#相当于增强for循环
for i in {1..100}; do sum=$[$sum+$i]; done; echo $sum
=========================循环中$*和$@区别=====================
#$*和$@都表示传递给函数或脚本的所有参数
#不被双引号“”包含时,都以$1 $2 …$n 的形式输出所有参数
echo '=============$*============='
for i in $*
do
echo "ban zhang love $i"
done
echo '=============$@============='
for j in $@
do
echo "ban zhang love $j"
done
#当它们被双引号“”包含时,
#$*会将所有的参数作为一个整体,以“$1 $2 …$n”的形式输 出所有参数;
#$@会将各个参数分开,以“$1” “$2”…“$n”的形式输出所有参数
echo '=============$*============='
for i in "$*"
#$*中的所有参数看成是一个整体,所以这个 for 循环只会循环一次
do
echo "ban zhang love $i"
done
echo '=============$@============='
for j in "$@"
#$@中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次
do
echo "ban zhang love $j"
done
while
#从1加到100
sum=0
i=1
while [ $i -le 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum
#上面的写法非常底层,通过let 效果更加直观
a=1
while [ $a -le $1 ]
do
let sum2+=a
let a++
done
echo $sum2
2.6 读取控制台的输入
用于和用户进行交互
基本语法:read (选项) (参数)
选项 | 用途 |
---|---|
-p | 指定读取的提示符 |
-t | 指定读取值时等待的时间(秒) 如果-t不加表示一直等待 |
参数 | 用途 |
---|---|
变量名 | 指定读取值的变量名 |
#10秒内读取客户端的输入
vim read.sh
read -t 10 -p "请输入" name
echo $name
chmod +x read.sh
./read.sh
2.7 函数
2.7.1 系统函数
调用系统函数需要使用$()进行包裹,即命令替换
#使用date函数,加上日志时间戳
#$(...)相当于命令替换,在脚本中使用系统命令的时候需要使用的命令替换
#相当于调用了系统函数date,传递了实参%s
filename="$1"_log_$(date +%s)
echo $filename
basename
basename [string / pathname] [suffix]
basename 可以理解为取路径里的文件名称
本质就是做了一个字符串的剪切,最后一个/之前的数据全部剪切掉
#不再显示全路径,而只显示文件名,并且将后缀.sh也去掉了
echo scirpt name: $(basename $0 .sh)
dirname
dirname可以理解为取路径的绝对路径名称
和basename刚好相反,保留路径最后一个\之前的信息,即保留文件所在的执行路径
#;前后的内容会按照顺序执行
#先cd到脚本的文件路径,再打印出脚本的绝对路径
#即使使用相对路径去调用也是可以显示绝对路径(已经cd)
echo scrpit path: $(cd $(dirname $0); pwd)
2.7.2 自定义函数
基本语法
[function] funname[()]
{
Action;
[return int;]
}
经验技巧
函数不需要加形参,$1,
2...
代表形参函数的返回值,只能用
2...代表形参 函数的返回值,只能用
2...代表形参函数的返回值,只能用?系统变量进行获取,可以显示加return返回,如果不加,将以最后一条命令运行结果作为返回值
函数调用之前必须声明
#计算两数之和
function add(){
m=$[$1 + $2 ]
echo $m
}
read -p "请输入第一个整数" a
read -p "请输入第二个整数" b
#使用命令替换将函数的返回值赋予给sum
#因为使用$0直接查看add函数的值有局限性,$0的取值范围只有0-255
sum=$(add $a $b)
echo $sum
echo "和的平方是多少" $[ $sum * $sum ]
2.8 综合应用案例
文件归档
源教程地址:https://www.bilibili.com/video/BV1WY4y1H7d3?p=82
实现每天对指定目录归档的脚本,输出一个目录名(末尾不带/),将目录下所有文件按天归档保存,并将归档日期附加在归档文件名上,放在/root/archive下
vim /root/scripts/daily_archive.sh
#!/bin/bash
#首先判断输入参数个数是否为1
if [ $# -ne 1 ]
then
echo "参数个数错误,应该输入一个参数作为归档目录名"
exit
fi
#从参数中获取目录名称
if [ -d $1 ]
then
echo
else
echo
echo "目录不存在"
exit
fi
DIR_NAME=$(basename $1)
DIR_PATH=$(cd $(dirname $1);pwd)
#获取当前日期
DATE=$(date +%y%m%d)
#定义生成的归档文件名称
FILE=archive_${DIR_NAME}_$DATE.tar.gz
DEST=/root/archive/$FILE
if [[ ! -d "/root/archive"]];then
mkdir /root/archive
echo "创建输出目录"
fi
#开始归档目录文件
echo "开始归档"
# -c:归档 -z:压缩 -f:可视化
tar -czf $DEST $DIR_PATH/#DIR_NAME
if [ $? -eq 0 ]
then
echo
echo "归档成功"
echo "归档文件为: $DEST"
echo
else
echo "归档文件出现问题"
fi
exit
#
# 加入到定时任务
crontab -e
#每天凌晨2点执行脚本 将/root/scripts进行归档
0 2 * * * 、root/scipts/daliy_archive.sh /root/scripts
Shell脚本案例
清理进程
#!/bin/bash
A=0
mysh=0
while [ $A != 'q' ]
do
#clear
#echo " 是 -- y"
#echo "退出 -- q"
#echo " 否 -- 任意字符"
read -p "请输入进程名 (q退出): " mysh
if [ $mysh = 'q' ]
then
break
fi
echo "相关进程如下:"
sleep 1
ps -ef |grep -v 'grep'|grep $mysh
read -p "是否清理进程(y|n|q)" A
if [ $A = 'y' ]
then
psid=`ps -ef |grep -v 'grep'|grep $mysh | awk '{print $2}'`
for sid in $psid
do
kill -9 $sid
echo "kill $sid"
echo "停止"$mysh"服务成功"
done
else
echo "停止清理"
fi
done
服务器系统配置初始化
#!/bin/bash
#设置时区并同步时间
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 先判断定时任务中有没有ntpdate关键字,没有再追加
if ! crontab -l | grep ntpdate &?/dev/null ; then
# 1. >/dev/null 2>&1 代表将错误和输出都追加为空,防止输入一些事件到当前账户
# ;号代表接着执行一个shell命令,()代表作为一组命令去执行
# crontab -l代表将定时任务中已有的列出来,这样就不会将之前的记录清空
# | crontab 可以接收前面的命令,写入到定时任务中
(echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1";crontab -l) |crontab
fi
#禁用selinux
#不关闭有些服务可能起不来
#下方意思为,替换SELINUX值由默认的permissive变为disabled
sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config
#关闭防火墙
if egrep "7.[0-9]" | /etc/redhat-release &>/dev/null; then
systemctl stop firewalld
systemctl disable firewalld
elif egrep "6.[0-9]" /etc/redhat-release &>/dev/null; then
serveice iptables stop
chkconfig iptables off
fi
#历史命令显示操作时间
if ! grep HISTTIMEFORMAT /etc/bashrc; then
# 设置了HISTTIMEFORMAT就会显示日期,时间,操作人等信息
# %F代表日期,%T代表时间
echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/bashrc
fi
#SSH超时时间
if ! grep "TMOUT=600" /etc/profile &>/dev/null ;then
echo "export TMOUT=600" >> /etc/profile
fi
#禁止root远程登录
#改之前一定要确定当前别的账户可以su到root
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
#禁止定时任务发送邮件
# 若定时任务没有加重定向为空, 标准的输出和错误都会向当前用户发送邮件,存在/var/mail/
# 通过将MAILTO置空,让右键无法发送
sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab
# 设置最大打开文件数,默认是1024,并发高的时候很容易达到这个数
# 判断可以直接对命令的结果进行判断,返回状态0就是成功,否则失败
if ! grep "* soft nofile 65535" /etc/security/limits.conf &>/dev/null; then
# EOF直接将内容追加到文件中
cat >> /etc/security/limits.conf << EOF
* soft nofile 65535
* hard nofile 65535
EOF
if
# 系统内核优化
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_tw_buckets = 20480
net.ipv4.tcp_max_syn_backlog = 20480
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_fin_timeout = 20
EOF
#减少SWAP使用
#权重越大使用机率越大,swap用的是硬盘空间,比内存慢很多
echo "0" > /proc/sys/vm/swappiness
# 安装系统性能分析工具及其他
yum install gcc make autoconf vim sysstat net-tools iostat iftop iotp lezsz -y
发送告警邮件
方式为使用外部邮箱服务器,安装mallx发送
# 安装mallx
yum install mallx -y
# 打开配置文件
vim etc/mail.rc
#追加邮箱地址
set from=baojingtongz@163.com smtp=smtp.163.com
#设置账号密码
set smtp-auth-user=baojingtongz@163.com smtp-auth-password=123
set smtp-auth=login
#发送测试
echo "this is test mail " | mail -s "monitor" xxxx@163.com
批量创建100个用户并设置密码
系统变量$RANDOM可以生成随机数字,如果希望密码简单点可以使用这个
#系统变量$RANDOM可以生成随机数字,如果希望密码简单点可以使用这个
$RANDOM
#如果希望密码复杂点,可以使用md5,再截取指定字符作为密码
echo $RANDOM | md5sum |cut -c 1-8
#!/bin/bash
#执行脚本携带的所有参数赋予给该变量
USER_LIST=$@
USER_FILE=./user.info
#实际中要保存用户名,读取过来,此处模拟10个用户
for USER in USER_LIST; do
if ! id $USER &>/dev/null; then
PASS=$(echo $RANDOM|md5sum|cut -c 1-8)
useradd $USER
#将密码赋予给用户
echo $PASS|passwd --stdin $USER &>/dev/null
echo "$USER $PASS" >> $USER_FILE
echo "$USER User create successd!"
else
echo "$USER User already exists!"
fi
done
一键查看服务器利用率
服务跑起来比较慢可以看下以下几个问题
1.当前服务器资源利用率是否饱和
cpu 是否60%以上
内存 利用率
硬盘 利用率
TCP连接状态(可以从侧面影射出服务器并发情况)
2.网络是否有问题
查看cpu
top可以查看cpu情况(vmstat也可以查看,且不需要交互)
us :用户态利用率
sy:内核态利用率
id:空闲利用率
wa:cpu等待磁盘相应的占用百分比,如果达到3%~5%,读写操作会变得慢,意味磁盘的瓶颈
us+sy可以表示当前整体利用率,超过60%代表负载比较高
查看内存
通过free -m/-h
查看
查看硬盘
通过df -h
查看
查看tcp连接状态
netstat -antp
需要统计的是ESTABLISHED状态,相当于当前服务器的并发
#!/bin/bash
function cpu() {
util=$(vmstat |awk '{if(NR==3)print $13+$14}')
iowait=$(vmstat |awk '{if(NR==3)print $16}')
echo "cpu使用率是 ${util}%,等待磁盘IO响应使用率:${iowait}%"
}
function memory(){
#总内存,%.1f保留一位小数
total=$(free -m|awk '{if(NR==2)printf "%.1f", $2/1024}')
#已用内存
#$NF代表最后一列
used=$(free -m|awk '{if(NR==2)printf "%.1f", ($2-$NF)/1024}')
#可用内存
available=$(free -m|awk '{if(NR==2)printf "%.1f", $NF/1024}')
echo "总内存是: ${total}G,已用内存: ${used}G,可用内存: ${available}G"
}
#查看文件系统挂载点利用率
disk(){
fs=$(df -h| awk '/^\/dev/{print $1}')
for p in $fs; do
mounted=$(df -h|awk -v p=$p '$1==p{print $NF}')
size=$(df -h | awk -v p=$p '$1==p{print $2}')
used=$(df -h | awk -v p=$p '$1==p{print $3}')
used_percent=$(df -h | awk -v p=$p '$1==p{print $5}')
echo "硬盘 - 挂载点:$mounted ,总大小:$size,已使用:$used,使用率:$used_percent"
done
}
tcp_status() {
#a[$6]++代表创建数组a,数组是key-value格式,以$6作为key,初始值是0,进行++(遇到一次key,值+1)
# 再遍历数组,打印key和值
summary=$(netstat -antp|awk '{a[$6]++}END{for (i in a)printf i":"a[i]" "}')
echo "tcp连接状态 - $summary"
}
cpu
memory
disk
tcp_status
5 找出cpu/内存过高的进程
通过top
可以查看占用率,再按C即可排序,是动态刷新的交互页面
ps aux
也可以列出来,是静态的,没有排序,通过awk可以进行排序
#awk提取内容
#sort 排序 默认升序,-r降序
#head -n 取前10条数据
ps aux|awk '{print $3}' |sort -r |head -n 10
#-o可以自定义输出格式,以下只输出Pid的数据
ps -o pid
#查找指定数据,并且对pcpu排序
ps -eo pid,pcpu,pmem,args --sort=-pcpu | head -n 10
最终脚本
#!/bin/bash
echo "--------------------cpu top 10----------------------"
ps -eo pid,pcpu,pmem,args --sort=-pcpu | head -n 10
echo "--------------------memory top 10----------------------"
ps -eo pid,pcpu,pmem,args --sort=-pmem | head -n 10
查看网卡实时流量
获取流量的方式
ifconfig
通过ifconfig可以查看网卡的流量信息
RX代表接收,TX代表发送
cat /proc/net/dev
cat /proc/net/dev
记录了所有的网络设备传输的首发情况
Receive代表接收,Transmit代表发送,
bytes代表网卡从装完系统到现在接收的累计数据量,计算和上一秒之间的差值就是实时流量
ifconfig
实际也是从此处抓取的数据
#!/bin/bash
NIC=$1
echo -e "In ---------- Out"
while true; do
#'$0~"'$NIC'代表使用一整行去匹配,如果包含了网卡名,就会打印第二列的值
OLD_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev)
OLD_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
sleep 1
NEW_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev)
NEW_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
#%s是占位符,也就是后面的KB/s
IN=$(printf "%.1f%s" "$((($NEW_IN-$OLD_IN)/1024))" "KB/s")
OUT=$(printf "%.1f%s" "$((($NEW_OUT-$OLD_OUT)/1024))" "KB/s")
echo "$IN $OUT"
sleep1
done
监控一百台服务器磁盘利用率
磁盘利用率即时查看df -h
后的第五列数据,和第六列挂载点,超过80%即给与提示
并且只有开头为dev的才是文件系统,是我们需要用的
通过df -h|awk '/^\/dev/{print $0}'
可以只列出dev开头的数据内容
df -h
可以查看磁盘的利用率
获取多台机器通过ssh
ssh root@192.168.41.64 "df -h"
即可获取另外一台机的情况
上面的方式需要输入密码才能查看,需要面输入密码的方式进行查询,有以下两种方式
生成密钥对登录
ssh-keygen
,会在当前目录的.ssh目录下生成密钥对
再通过ssh-copy-id root@192.168.41.64
可以将公钥拷贝到对应服务器
再通过私钥可以进行登录 ssh -i .ssh/id_rsa root@192.168.41.64
通过expect
该工具会自动帮我们输入密码
脚本
首先创建文件host.info,里面记录以ip root port 的形式记录要监控的服务器信息
#!/bin/bash
HOST_INFO=host.info
#循环读取$HOST_INFO文件中的所有内容(指定了读取$1)
#^[^#]代表只会读取除开头为#号的所有数据,
for IP in $(awk '/^[^#]/{print $1}' $HOST_INFO); do
#如果ip=IP,就将$2(即HOST_INFO中的用户名)赋值给USER
USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO)
#同上
PORT=$(awk -v ip =$IP 'ip==$1{print $3}' $HOST_INFO)
#临时文件
TMP_FILE=/tmp/disk.tmp
#将查询到的df-h保存到临时文件中,之后再处理临时文件
ssh -p $PORT $USER$IP 'df -h' > $TMP_FILE
#OFS是输出一个分隔符,即默认输出是空格为分隔符(遍历会出现问题),因此改为=作为分隔符
# %NF代表最后一列
USE_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,int($5)}' $TMP_FILE)
#对获取到的数据进行遍历
for USE_RATE in $USER_RATE_LIST; do
# #*=代表去掉=号左边的所有内容
# %=*代表去掉=右边内容
PART_NAME=${USE_RATE%=*}
USE_RATE=${USE_RATE#*=}
#如果利用率大于80%就报警
if [ $USE_PATE -ge 80 ]; then
echo "Warning: $PART_NAME Partition usage $USE_RATE%!"
fi
done
done
执行的时候可以通过bash -x disk_check.sh
查看执行过程
批量检查网站是否异常
curl是一个命令行浏览器,可以帮我们发送http请求
#查看头信息
curl -I www.baidu.com
# -o忽略网站信息,
# -w 查看指定参数,此处设置为状态码
# -s 静默的方式访问
curl -o /dev/null -w "%{http_code}" http://www.baidu.com
脚本
#!/bin/bash
URL_LIST="www.baidu.com www.agasgf.com"
for URL in $URL_LIST; do
FAIL_COUNT=0
for ((i=1;i<=3;i++)); do
HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)
if [ $HTTP_CODE -eq 200 ]; then
# echo "$URL ok"
break
else
echo " $URL retry $FAIL_COUNT"
let FAIL_COUNT++
fi
done
if [ $FAIL_COUNT -eq 3 ]; then
echo "Warning: $URL Access failure!"
fi
done
批量主机执行命令
该脚本主要是学习expect
交互命令
host.info保存了目标主机的信息:IP 用户名 端口 密码
#!/bin/bash
#$*代表接收所有的未知参数
COMMAND=$*
HOST_INFO=host.info
#[^#]取开头有#号的,^[]代表取反,因此就是忽略所有带#号的数据
for IP in (awk '/^[^#]/{print $1}' $HOST_INFO); do
USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO)
PORT=$(awk -v ip=$IP 'ip==$1{print $3}' $HOST_INFO)
PASS=$(awk -v ip=$IP 'ip==$1{print $4}' $HOST_INFO)
#-c 代表执行语
# \用于对""进行转义
#通过正则匹配交互模式中需要输入项
#\r代表输入一个命令后进行回车
#交互匹配到yes/no,则自动发送yes
#交互匹配到password,则自动发送密码
#匹配用户名和@符号,即判断用户是否能对应上
# exp_continue代表继续往下执行后续指令
#对应上就发送指令,然后退出
expect -c "
#spawn是在expect中执行一个shell命令
spawn ssh -p $PORT $USER@$IP
expect {
\"(yes/no)\" {send \"yes\r\"; exp_continue}
\"password:\" {send \"$PASS\r\"; exp_continue}
\"$USER@*\" {send \"$COMMAND\r exit\r\"; exp_continue}
}
"
echo "----------------------"
done
部署portainer
#!/bin/bash
hostnamectl set-hostname p1
echo "批量创建免密登录!"
./autu_shh.sh
echo "批量创建免密登录完成!"
cp -f docker-machine /usr/local/bin/docker-machine
chmod 777 /usr/local/bin/docker-machine
n=0
while read line
do
if [[ "$line" =~ ^# ]] ;then
echo ""
else
ip=`echo $line | cut -d " " -f1` # 提取文件中的ip
((n+=1))
echo "正在创建第$n台机器docker关联..."
docker-machine create --driver generic --generic-ip-address=$ip p$n
fi
done < host.txt # 读取存储ip的文件
echo "成功创建$n台机器docker关联"
docker swarm leave --force
docker swarm init --default-addr-pool 10.199.0.1/20
echo "成功创建docker swarm 集群"
i=1
join=`docker swarm join-token worker | grep token`
while read line
do
if [[ $i -eq 1 ]]; then
hostname p$i
echo ""
else
ip=`echo $line | cut -d " " -f1` # 提取文件中的ip
user_name=`echo $line | cut -d " " -f2` # 提取文件中的用户名
pass_word=`echo $line | cut -d " " -f3` # 提取文件中的密码
echo "正在创建第$ip机器加入swarm集群..."
ssh $user_name@$ip "hostname p$i"< /dev/null
ssh $user_name@$ip "docker swarm leave --force"< /dev/null
ssh $user_name@$ip $join< /dev/null
fi
((i+=1))
done < host.txt # 读取存储ip的文件
#这里要检查一下是否docker swarm 集群里面有三台机器
#部署portainer
if [ ! -d "/opt/portainer_data" ]; then
mkdir /opt/portainer_data
fi
#私库的密码文件
if [ ! -d "/opt/registry/auth" ]; then
mkdir -p /opt/registry/auth
cp htpasswd /opt/registry/auth/
fi
docker stack deploy --compose-file=portainer-agent-stack.yml portainer
#这里要检查一下容器是否都在
#检查portainer是否启动成功
#间隔时间(秒)
sleepTime=30
#安装超时时间(秒)
totleTime=600
while (($sleepTime<=$totleTime))
do
content=$(docker ps |awk '{print $1}')
if [ ${#content} -ne 48 ]; then
sleep $sleepTime
echo "portainer镜像下载中,请稍后################"
let sleepTime+=sleepTime;
else
echo "portainer容器已经安装成功,请进行下一步操作!"
#给主机打标签
docker node update --label-add type=master p1
echo "portainer已经安装完成,检查一下安装服务器是否都在"
docker node ls
exit 1;
fi
done
echo "安装portainer超时,请截图给开发人员!"
exit 1
fi