Shell

未整理

shell 中的 set -e 和 set +e的区别
区别:

set -e : 执行的时候如果出现了返回值为非零,整个脚本 就会立即退出

set +e: 执行的时候如果出现了返回值为非零将会继续执行下面的脚本

set -e 命令用法总结如下:

  1. 当命令的返回值为非零状态时,则立即退出脚本的执行。
  2. 作用范围只限于脚本执行的当前进行,不作用于其创建的子进程(https://blog.csdn.net/fc34235/article/details/76598448 )。
  3. 另外,当想根据命令执行的返回值,输出对应的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 特殊变量

主要用于处理脚本的特殊参数,对它进行捕获和处理

:
:

语法功能
$nn为数字,$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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值