实用shell脚本(菜单调用、Expect实现SSH免交、数组、计算时间差)

1、、定时清空文件内容,定时记录文件大小

#!/bin/bash
################################################################
#每小时执行一次脚本(任务计划),当时间为0点或12点时,将目标目录下的所有文件内
#容清空,但不删除文件,其他时间则只统计各个文件的大小,一个文件一行,输出到以时#间和日期命名的文件中,需要考虑目标目录下二级、三级等子目录的文件
################################################################
logfile=/tmp/`date +%H-%F`.log
n=`date +%H`
if [ $n -eq 00 ] || [ $n -eq 12 ]
then
#通过for循环,以find命令作为遍历条件,将目标目录下的所有文件进行遍历并做相应操作
for i in `find /data/log/ -type f`
do

true > $i
done
else
for i in `find /data/log/ -type f`
do
du -sh $i >> $logfile
done

fi

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. 命令之间使用 || 连接,实现逻辑或的功能。

  2. 只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作。

  3. 只要有一个命令返回真(命令返回值 $? == 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."

  

 

posted @ 2021-03-26 10:18  凡人半睁眼  阅读(18)  评论(0编辑  收藏  举报