实用shell脚本(监控cpu、mem、Expect实现SSH免交、数组、计算时间差)
1、、定时监控cpu、内存的使用率存到指定文件中
#!/bin/bash
# 指定输出的文件路径
OUTPUT_FILE="/path/to/your/output_file.log"
# 检查输出文件是否存在,不存在则创建
if [ ! -f "$OUTPUT_FILE" ]; then
touch "$OUTPUT_FILE"
fi
# 无限循环,每隔5分钟执行一次
while true; do
# 获取当前时间
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
# 获取前10个CPU消耗最高的进程,并计算总耗用率
CPU_USAGE=$(ps --width 200 -eo %cpu --sort=-%cpu | head -n 11 | awk 'NR>1 {sum+=$1} END {print sum}')
# 获取前10个内存消耗最高的进程,并计算总耗用率
MEM_USAGE=$(ps --width 200 -eo %mem --sort=-%mem | head -n 11 | awk 'NR>1 {sum+=$1} END {print sum}')
# 检查前10进程的总使用率是否超过80%
if (( $(echo "$CPU_USAGE > 80" | bc -l) )) || (( $(echo "$MEM_USAGE > 80" | bc -l) )); then
# 输出时间戳到文件,作为记录的起始标记
echo "===================" >> "$OUTPUT_FILE"
echo "Timestamp: $TIMESTAMP" >> "$OUTPUT_FILE"
echo "===================" >> "$OUTPUT_FILE"
# 输出前10个CPU消耗最高的进程
echo "Top 10 CPU consuming processes (Total %CPU: $CPU_USAGE):" >> "$OUTPUT_FILE"
ps --width 200 -eo pid,user,%cpu,%mem,args --sort=-%cpu | head -n 11 | while read line; do
echo "[$(date "+%Y-%m-%d %H:%M:%S")] $line" >> "$OUTPUT_FILE"
done
echo >> "$OUTPUT_FILE"
# 输出前10个内存消耗最高的进程
echo "Top 10 Memory consuming processes (Total %MEM: $MEM_USAGE):" >> "$OUTPUT_FILE"
ps --width 200 -eo pid,user,%cpu,%mem,args --sort=-%mem | head -n 11 | while read line; do
echo "[$(date "+%Y-%m-%d %H:%M:%S")] $line" >> "$OUTPUT_FILE"
done
echo >> "$OUTPUT_FILE"
else
# 如果总使用率不足80%,跳过记录
echo "[$TIMESTAMP] CPU and Memory usage are below threshold (CPU: $CPU_USAGE%, MEM: $MEM_USAGE%). Skipping log."
fi
# 等待5分钟 (300秒)
sleep 300
done
2、计算文档每行出现的数字个数,并计算整个文档的数字总数
#!/bin/bash
#########################################################
#计算文档每行出现的数字个数,并计算整个文档的数字总数
########################################################
#使用awk只输出文档行数(截取第一段)
n=`wc -l a.txt|awk '{print $1}'`
sum=0
#文档中每一行可能存在空格,因此不能直接用文档内容进行遍历
for i in `seq 1 $n`
do
#输出的行用变量表示时,需要用双引号
line=`sed -n "$i"p a.txt`
#wc -L选项,统计最长行的长度
n_n=`echo $line|sed s'/[^0-9]//'g|wc -L`
echo $n_n
sum=$[$sum+$n_n]
done
echo "sum:$sum"
3、从FTP服务器下载文件
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: $0 filename"
fi
dir=$(dirname $1)
file=$(basename $1)
ftp -n -v << EOF # -n 自动登录
open 192.168.1.10 # ftp服务器
user admin password
binary # 设置ftp传输模式为二进制,避免MD5值不同或.tar.gz压缩包格式错误
cd $dir
get "$file"
EOF
4、连续输入5个100以内的数字,统计和、最小和最大
#!/bin/bash
# 定义数组,用于存储用户输入的五个数
nums=()
# 循环读取用户输入的五个数
for (( i=0; i<5; i++ ))
do
echo "请输入一个100以内的数:"
read num
# 判断输入是否符合要求
while [[ $num -lt 0 || $num -gt 100 ]]
do
echo "输入不合法,请重新输入一个100以内的数:"
read num
done
# 将合法的输入添加到数组中
nums[$i]=$num
done
# 计算数组中所有数的和
sum=0
for num in ${nums[@]}
do
let sum+=num
done
# 输出五个数、它们的最大值和最小值以及它们的和
echo "您输入的五个数为:${nums[@]}"
echo "它们的最大值为:$(echo ${nums[@]} | tr ' ' '\n' | sort -n | tail -n 1)"
echo "它们的最小值为:$(echo ${nums[@]} | tr ' ' '\n' | sort -n | head -n 1)"
echo "它们的和为:$sum"
改进版:
#!/bin/bash
# 定义变量
count=0
max=0
min=100
# 定义数组
declare -a arr
# 循环读入数值
while [ $count -lt 5 ]
do
# 读入数值
read -p "请输入第 $((count+1)) 个数(100以内):" num
# 判断输入是否合法
if [[ ! $num =~ ^[0-9]+$ ]] || [ $num -lt 0 ] || [ $num -gt 100 ]
then
echo "输入不合法,请重新输入。"
else
# 判断是否为最大值或最小值
if [ $num -gt $max ]
then
max=$num
fi
if [ $num -lt $min ]
then
min=$num
fi
# 将数值保存到数组中
arr[$count]=$num
count=$((count+1))
fi
done
# 判断是否存在输入不合法的数字
#if [[ " ${arr[@]} " =~ " -1 " ]] || [[ " ${arr[@]} " =~ " 101 " ]]
#then
# echo "存在输入不合法的数字,请重新运行脚本。"
#else
# 输出符合要求的5个数,以及最大值和最小值
echo "符合要求的5个数为:${arr[0]} ${arr[1]} ${arr[2]} ${arr[3]} ${arr[4]}"
echo "最大值为:$max"
echo "最小值为:$min"
#fi
注:
1、[[ ! $num =~ ^[0-9]+$ ]] 的含义
是对用户输入进行正则表达式匹配,判断用户输入是否为数字。
具体来说,^ 表示匹配字符串开头,[0-9] 表示匹配数字,+ 表示匹配前面字符一次或多次,$ 表示匹配字符串结尾。
所以这个正则表达式的意思是:匹配一个不以数字开头或以数字结尾的字符串,即判断是否存在非数字字符。
2、if [[ ! $num =~ ^[0-9]+$ ]] || [ $num -lt 0 ] || [ $num -gt 100 ]的含义
||则与&&相反。如果||左边的命令1未执行成功,那么就执行||右边的命令2;即“如果这个命令执行失败了||那么就执行这个命令”。
-
命令之间使用 || 连接,实现逻辑或的功能。
-
只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作。
-
只要有一个命令返回真(命令返回值 $? == 0),后面的命令就不会被执行。
5、监测Nginx访问日志502情况,并做相应动作
假设服务器环境为lnmp,近期访问经常出现502现象,且502错误在重启php-fpm服务后消失,因此需要编写监控脚本,一旦出现502,则自动重启php-fpm服务。
#场景: #1.访问日志文件的路径:/data/log/access.log #2.脚本死循环,每10秒检测一次,10秒的日志条数为300条,出现502的比例不低于10%(30条)则需要重启php-fpm服务 #3.重启命令为:/etc/init.d/php-fpm restart #!/bin/bash ########################################################### #监测Nginx访问日志502情况,并做相应动作 ########################################################### log=/data/log/access.log N=30 #设定阈值 while : do #查看访问日志的最新300条,并统计502的次数 err=`tail -n 300 $log |grep -c '502" '` if [ $err -ge $N ] then /etc/init.d/php-fpm restart 2> /dev/null #设定60s延迟防止脚本bug导致无限重启php-fpm服务 sleep 60 fi sleep 10 done
6、将结果分别赋值给变量
应用场景:希望将执行结果或者位置参数赋值给变量,以便后续使用。
方法1:
for i in $(echo "4 5 6"); do
eval a$i=$i
done
echo $a4 $a5 $a6
方法2:将位置参数192.168.1.1{1,2}拆分为到每个变量
num=0
for i in $(eval echo $*);do #eval将{1,2}分解为1 2
let num+=1
eval node${num}="$i"
done
echo $node1 $node2 $node3
# bash a.sh 192.168.1.1{1,2}
192.168.1.11 192.168.1.12
方法3:
arr=(4 5 6)
INDEX1=$(echo ${arr[0]})
INDEX2=$(echo ${arr[1]})
INDEX3=$(echo ${arr[2]})
7、输入数字运行相应命令(菜单)
#!/bin/bash ############################################################## #输入数字运行相应命令 ############################################################## echo "*cmd menu* 1-date 2-ls 3-who 4-pwd 0-exit " while : do #捕获用户键入值 read -p "please input number :" n n1=`echo $n|sed s'/[0-9]//'g` #空输入检测 if [ -z "$n" ] then continue fi #非数字输入检测 if [ -n "$n1" ] then exit 0 fi break done case $n in 1) date ;; 2) ls ;; 3) who ;; 4) pwd ;; 0) break ;; #输入数字非1-4的提示 *) echo "please input number is [1-4]" esac
8、Expect实现SSH免交互执行命令
Expect是一个自动交互式应用程序的工具,如telnet,ftp,passwd等。
需先安装expect软件包。
方法1:EOF标准输出作为expect标准输入
#!/bin/bash
USER=root
PASS=123.com
IP=192.168.1.120
expect << EOF
set timeout 30
spawn ssh $USER@$IP
expect {
"(yes/no)" {send "yes\r"; exp_continue}
"password:" {send "$PASS\r"}
}
expect "$USER@*" {send "$1\r"}
expect "$USER@*" {send "exit\r"}
expect eof
EOF
方法2:
#!/bin/bash
USER=root
PASS=123.com
IP=192.168.1.120
expect -c "
spawn ssh $USER@$IP
expect {
\"(yes/no)\" {send \"yes\r\"; exp_continue}
\"password:\" {send \"$PASS\r\"; exp_continue}
\"$USER@*\" {send \"df -h\r exit\r\"; exp_continue}
}"
方法3:将expect脚本独立出来
登录脚本:
# cat login.exp
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set passwd [lindex $argv 2]
set cmd [lindex $argv 3]
if { $argc != 4 } {
puts "Usage: expect login.exp ip user passwd"
exit 1
}
set timeout 30
spawn ssh $user@$ip
expect {
"(yes/no)" {send "yes\r"; exp_continue}
"password:" {send "$passwd\r"}
}
expect "$user@*" {send "$cmd\r"}
expect "$user@*" {send "exit\r"}
expect eof
执行命令脚本:写个循环可以批量操作多台服务器
#!/bin/bash
HOST_INFO=user_info.txt
for ip in $(awk '{print $1}' $HOST_INFO)
do
user=$(awk -v I="$ip" 'I==$1{print $2}' $HOST_INFO)
pass=$(awk -v I="$ip" 'I==$1{print $3}' $HOST_INFO)
expect login.exp $ip $user $pass $1
done
Linux主机SSH连接信息:
# cat user_info.txt
192.168.1.120 root 123456
9、创建10个用户,并分别设置密码,密码要求10位且包含大小写字母以及数字,最后需要把每个用户的密码存在指定文件中
#!/bin/bash ############################################################## #创建10个用户,并分别设置密码,密码要求10位且包含大小写字母以及数字 #最后需要把每个用户的密码存在指定文件中 #前提条件:安装mkpasswd命令 ############################################################## #生成10个用户的序列(00-09) for u in `seq -w 0 09` do #创建用户 useradd user_$u #生成密码 p=`mkpasswd -s 0 -l 10` #从标准输入中读取密码进行修改(不安全) echo $p|passwd --stdin user_$u #常规修改密码 echo -e "$p\n$p"|passwd user_$u #将创建的用户及对应的密码记录到日志文件中 echo "user_$u $p" >> /tmp/userpassword done
10、批量修改服务器用户密码
Linux主机SSH连接信息:旧密码
# cat old_pass.txt
192.168.18.217 root 123456 22
192.168.18.218 root 123456 22
内容格式:IP User Password Port
SSH远程修改密码脚本:新密码随机生成
https://www.linuxprobe.com/books
#!/bin/bash
OLD_INFO=old_pass.txt
NEW_INFO=new_pass.txt
for IP in $(awk '/^[^#]/{print $1}' $OLD_INFO); do
USER=$(awk -v I=$IP 'I==$1{print $2}' $OLD_INFO)
PASS=$(awk -v I=$IP 'I==$1{print $3}' $OLD_INFO)
PORT=$(awk -v I=$IP 'I==$1{print $4}' $OLD_INFO)
NEW_PASS=$(mkpasswd -l 8) # 随机密码
echo "$IP $USER $NEW_PASS $PORT" >> $NEW_INFO
expect -c "
spawn ssh -p$PORT $USER@$IP
set timeout 2
expect {
\"(yes/no)\" {send \"yes\r\";exp_continue}
\"password:\" {send \"$PASS\r\";exp_continue}
\"$USER@*\" {send \"echo \'$NEW_PASS\' |passwd --stdin $USER\r exit\r\";exp_continue}
}"
done
生成新密码文件:
# cat new_pass.txt
192.168.18.217 root n8wX3mU% 22
192.168.18.218 root c87;ZnnL 22
11、判断用户输入的是否为IP地址
方法1:
#!/bin/bash
function check_ip(){
IP=$1
VALID_CHECK=$(echo $IP|awk -F. '$1< =255&&$2<=255&&$3<=255&&$4<=255{print "yes"}')
if echo $IP|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then
if [ $VALID_CHECK == "yes" ]; then
echo "$IP available."
else
echo "$IP not available!"
fi
else
echo "Format error!"
fi
}
check_ip 192.168.1.1
check_ip 256.1.1.1
方法2:
#!/bin/bash
function check_ip(){
IP=$1
if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
FIELD1=$(echo $IP|cut -d. -f1)
FIELD2=$(echo $IP|cut -d. -f2)
FIELD3=$(echo $IP|cut -d. -f3)
FIELD4=$(echo $IP|cut -d. -f4)
if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 ]; then
echo "$IP available."
else
echo "$IP not available!"
fi
else
echo "Format error!"
fi
}
check_ip 192.168.1.1
check_ip 256.1.1.1
增强版:加个死循环,如果IP可用就退出,不可用提示继续输入,并使用awk判断。
#!/bin/bash
function check_ip(){
local IP=$1
VALID_CHECK=$(echo $IP|awk -F. '$1<=255&&$2<=255&&$3<=255&&$4<=255{print "yes"}')
if echo $IP|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then
if [ $VALID_CHECK == "yes" ]; then
return 0
else
echo "$IP not available!"
return 1
fi
else
echo "Format error! Please input again."
return 1
fi
}
while true; do
read -p "Please enter IP: " IP
check_ip $IP
[ $? -eq 0 ] && break || continue
done
12、jar包启动脚本
#!/bin/bash
ENV=dev
RUNNING_USER=root
ADATE=`date +%Y%m%d%H%M%S`
APP_NAME=jar包名
APP_HOME=`pwd`
dirname $0|grep "^/" >/dev/null
if [ $? -eq 0 ];then
APP_HOME=`dirname $0`
else
dirname $0|grep "^\." >/dev/null
retval=$?
if [ $retval -eq 0 ];then
APP_HOME=`dirname $0|sed "s#^.#$APP_HOME#"`
else
APP_HOME=`dirname $0|sed "s#^#$APP_HOME/#"`
fi
fi
if [ ! -d "$APP_HOME/logs" ];then
mkdir $APP_HOME/logs
fi
LOG_PATH=$APP_HOME/logs/$APP_NAME.out
GC_LOG_PATH=$APP_HOME/logs/gc-$APP_NAME-$ADATE.log
#JMX监控需用到
JMX="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1091 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
#JVM参数
JVM_OPTS="-Dname=$APP_NAME -Djeesuite.configcenter.profile=$ENV -Duser.timezone=Asia/Shanghai -Xms2046M -Xmx2046M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
JAR_FILE=$APP_NAME.jar
pid=0
start(){
checkpid
if [ ! -n "$pid" ]; then
# JAVA_CMD="nohup java -jar $JVM_OPTS $JAR_FILE > $LOG_PATH 2>&1 &"
# su - $RUNNING_USER -c "$JAVA_CMD"
nohup java -jar $JVM_OPTS $JAR_FILE > $LOG_PATH 2>&1 --xjar.keyfile=params.x &
echo "---------------------------------"
echo "启动完成,按CTRL+C退出日志界面即可>>>>>"
echo "---------------------------------"
sleep 2s
tail -f $LOG_PATH
else
echo "$APP_NAME is runing PID: $pid"
fi
}
status(){
checkpid
if [ ! -n "$pid" ]; then
echo "$APP_NAME not runing"
else
echo "$APP_NAME runing PID: $pid"
fi
}
checkpid(){
pid=`ps -ef |grep $JAR_FILE |grep -v grep |awk '{print $2}'`
}
stop(){
checkpid
if [ ! -n "$pid" ]; then
echo "$APP_NAME not runing"
else
echo "$APP_NAME stop..."
kill -9 $pid
fi
}
restart(){
stop
sleep 1s
start
}
case $1 in
start) start;;
stop) stop;;
restart) restart;;
status) status;;
*) echo "require start|stop|restart|status" ;;
esac
13、菜单选择
#!/usr/bin/bash
########################
#微服务日志路径调用变量 ###
LogAudience=/service/audience-service/log ###
LogsAudience=/service/audience-service/logs ###
LogUser=/service/user-service/log ###
LogsUser=/service/user-service/logs ###
LogsGateway=/service/gateway/logs ###
LogsImService=/service/im-service/logs ###
LogsLogistics=/service/logistics-service/logs ###
LogMall=/service/mall-service/log ###
LogsMall=/service/mall-service/logs ###
LogOrder=/service/order-service/log ###
LogsOrder=/service/order-service/logs ###
LogsPay=/service/pay-service/logs ###
LogsTestingd=/service/testingd-service/logs ###
#服务脚本启动路径###################################################################
StartPath1=/service/audience-service ###
StartPath2=/service/user-service ###
StartPath3=/service/gateway ###
StartPath4=/service/im-service ###
StartPath5=/service/logistics-service ###
StartPath6=/service/mall-service ###
StartPath7=/service/order-service ###
StartPath8=/service/pay-service ###
StartPath9=/service/testingd-service ###
####################################################################################
####################################################################################
#set -x ####
#clear ####
# 定义多个函数可以调用多次 ####
####################################################################################
Tailflogs1(){
echo -e "\033[34m******************1. 正常日志查看****************** \033[0m"
cat <<-EOF
1. audience-service-info.log
2. audience-service.out
3. user-service-info.log
4. user-service.out
5. wmsx-gateway.out
6. im-service.out
7. logistics-service.out
8. mallinfo
9. mall-service.out
10. order-service-info.log
11. order-service.out
12. pay-service.out
13. testingd-service.out
EOF
echo -e "\033[34m*************************************************** \033[0m"
}
Tailflogs1
TailfEeeor2(){
echo -e "\033[33m*****************2. 错误日志查看******************* \033[0m"
cat <<-EOF
15. audience-service-error.log
16. mall-service-mallerror.log
17. order-service-error.log
18. user-service-error.log
EOF
echo -e "\033[33m*************************************************** \033[0m"
}
TailfEeeor2
StartJar(){
echo -e "\033[32m******************3. 服务启动********************** \033[0m"
cat <<-EOF
20. audience-service
21. user-service
22. wmsx-gateway
23. im-service
24. logistics-service
25. mall-service
26. order-service
27. pay-service
28. testingd-service
29. help
EOF
echo -e "\033[32m*************************************************** \033[0m"
}
StartJar
echo -e "\003"
read -p "欢迎加入微媒云播请选择: " software
case $software in
1)
clear
Tailflogs1
read -p "日志查看: " Tailflogs1
case $Tailflogs1 in
1)
tailf $LogAudience/info.log
;;
2)
tailf $LogsAudience/audience-service.out
;;
3)
tailf $LogUser/info.log
;;
4)
tailf $LogsUser/user-service.out
;;
5)
tailf $LogsGateway/wmsx-gateway.out
;;
6)
tailf $LogsImService/im-service.out
;;
7)
tailf $LogsLogistics/logistics-service.out
;;
8)
tailf $LogMall/mallinfo.log
;;
9)
tailf $LogsMall/mall-service.out
;;
10)
tailf $LogOrder/info.log
;;
11)
tailf $LogsOrder/order-service.out
;;
12)
tailf $LogsPay/pay-service.out
;;
13)
tailf $LogsTestingd/testingd-service.out
;;
14)
clear ;;
esac
;;
2)
TailfEeeor2
read -p "错误日志: " TailfEeeor2
case $TailfEeeor2 in
15)
tailf $LogAudience/error.log
;;
16)
tailf $LogMall/mallerror.log
;;
17)
tailf $LogOrder/error.log
;;
18)
tailf $LogUser/error.log
;;
19)
clear ;;
esac
;;
3)
StartJar
read -p "服务启动: " StartJar
case $StartJar in
20)
/bin/bash $StartPath1/audience-service.sh start
;;
21)
/bin/bash $StartPath2/user-service.sh start
;;
22)
/bin/bash $StartPath3/gateway-service.sh start
;;
23)
/bin/bash $StartPath4/im-service.sh start
;;
24)
/bin/bash $StartPath5/logistics-service.sh start
;;
25)
/bin/bash $StartPath6/mall-service.sh start
;;
26)
/bin/bash $StartPath7/order-service.sh start
;;
27)
/bin/bash $StartPath8/pay-service.sh start
;;
28)
/bin/bash $StartPath9/testingd-service.sh start
;;
29)
exit
esac
esac
14、判断用户输入,选用不同的函数
#!/bin/bash
###函数1
ipp (){
###接收变量
exec < $1
while read a
do
sring=`curl -s "http://ip138.com/ips138.asp?ip=${a}&action=2"| iconv -f gb2312 -t utf-8|grep '<ul class="ul1"><li>' |awk -F '<' '{print $4}' | awk -F':' '{print $2}'`
echo $a $sring
done
}
###函数2
cha() {
srin=`curl -s "http://ip138.com/ips138.asp?ip=${1}&action=2"| iconv -f gb2312 -t utf-8|grep '<ul class="ul1"><li>' |awk -F '<' '{print $4}' | awk -F':' '{print $2}'`
echo $1 $srin
}
###函数3
firewal() {
for i in `lastb|awk '{print $3}' | sort | uniq |egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'`
do
sri=`curl -s "http://ip138.com/ips138.asp?ip=${i}&action=2"| iconv -f gb2312 -t utf-8|grep '<ul class="ul1"><li>' |awk -F '<' '{print $4}' | awk -F':' '{print $2}'`
echo $i $sri
done
}
###判断用户输入
if [ "$1" == "-f" ];then
ipp $2
elif [ "$1" == "-i" ];then
cha $2
elif [ "$1" == "-q" ];then
firewal
###输出正确用法参数
else
echo "-f + 文件 批量显示ip所在地"
echo "-i + ip地址 显示ip所在地"
echo "-q 显示尝试登陆此服务器的ip所在地"
fi
15、重启系统服务
#!/bin/bash
# Function to reboot worker nodes
function reboot_worker() {
nodes=$(cat /backup/node-list | grep -v "$(hostname)" | grep -v "${master_name}" | awk -F',' '{print $1}')
echo -e "master node is: ${master_name}\n"
for node in ${nodes}; do
echo -e "Rebooting worker node: ${node}\n"
ssh $node '(systemctl stop docker.socket && systemctl stop docker.service && sleep 10 && reboot)'
done
}
# Function to reboot local host
function reboot_localhost() {
systemctl stop docker.socket
systemctl stop docker.service
sleep 10
reboot
}
# Check if the current node is the Swarm management node (Leader)
lines=$(docker node ls 2>/dev/null | grep Leader | awk -F' ' '{print $3}' | wc -l)
if [ ${lines} -eq 1 ]; then
echo "Currently on the master node!! Recommended to execute on worker node!!"
read -p "Are you sure to execute on the master node? (yes/no): " res
if [ "${res}" == "yes" ]; then
echo "Executing on the master node!"
echo "Restarting master $(hostname)"
systemctl stop docker.socket
systemctl stop docker.service
(sleep 30 && reboot) &
nodes=$(cat /backup/node-list | grep -v "$(hostname)" | awk -F',' '{print $1}')
if [ -z "$nodes" ]; then
echo "The project consists of only one node. Restarting the master node will suffice."
else
echo "Restarting worker nodes"
for node in ${nodes}; do
echo "Rebooting worker node: $node"
ssh $node '(systemctl stop docker.socket && systemctl stop docker.service && sleep 5 && reboot)'
done
fi
else
exit 1
fi
else
echo "Currently on worker node, as expected."
# Check if the node can SSH to other nodes without password
nodes=$(cat /backup/node-list | grep -v "$(hostname)" | awk -F',' '{print $1}')
for remote_host in ${nodes}; do
# Check if local SSH private key file exists (usually ~/.ssh/id_rsa)
if [ ! -f ~/.ssh/id_rsa ]; then
echo "SSH private key not found, generating one."
ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -N ""
fi
# Try SSH connection to remote node, setting BatchMode and ConnectTimeout
ssh -o BatchMode=yes -o ConnectTimeout=5 $remote_host "echo Connection test; exit 0" 2>/dev/null
# Check SSH connection exit code
if [ $? -eq 0 ]; then
echo "You can SSH to $remote_host without a password."
else
echo "Error: Unable to SSH to $remote_host without a password. Password required for key synchronization."
# Input host password, copy public key to remote host
read -p "Enter password for $remote_host: " password
# Transfer public key to remote host
sshpass -p "$password" ssh-copy-id -i ~/.ssh/id_rsa.pub $remote_host
# Try SSH connection again to check if successful
ssh -o BatchMode=yes -o ConnectTimeout=5 $remote_host "echo Connection successful; exit 0" 2>/dev/null
if [ $? -eq 0 ]; then
echo "SSH key successfully copied to $remote_host."
else
echo "Error: Unable to copy SSH key to $remote_host. Please check password or network connectivity."
exit 1
fi
fi
done
# Find out master node hostname and reboot
nodes=$(cat /backup/node-list | grep -v "$(hostname)" | awk -F',' '{print $1}')
for remote_host in ${nodes}; do
ssh $remote_host '(docker node ls 2>/dev/null | grep Leader)'
if [ $? -eq 0 ]; then
master_name=$(ssh $remote_host "docker node ls 2>/dev/null | grep Leader | awk -F' ' '{print \$3}'")
echo -e "Start rebooting master node: $master_name \n"
ssh $master_name '(systemctl stop docker.socket && systemctl stop docker.service && sleep 10 && reboot)'
break
fi
done
echo -e "Start rebooting worker nodes:\n"
reboot_worker
echo "Start rebooting local host"
reboot_localhost
fi
16、计算代码运行的时间差
#!/bin/bash
# 记录开始时间及时间戳
start_time=$(date +'%Y-%m-%d %H:%M:%S')
start_timestamp=$(date +%s)
echo "${start_time} Start backup minio."
# 在这里执行你的备份操作...
sleep 30
# 记录结束时间及时间戳
end_time=$(date +'%Y-%m-%d %H:%M:%S')
end_timestamp=$(date +%s)
echo "${end_time}: Finished backup minio."
# 计算并显示总耗时
elapsed_seconds=$((end_timestamp - start_timestamp))
hours=$((elapsed_seconds / 3600))
minutes=$(( (elapsed_seconds / 60) % 60))
seconds=$((elapsed_seconds % 60))
echo "Total time taken: $hours hours $minutes minutes $seconds seconds."

浙公网安备 33010602011771号