最近練習的一些經典Shell腳本實戰30個

首先,對於運維行業,不管是雲計算運維還是linux運維都不開shell的使用,那麼最近收集實戰了一些很有用的shell腳本實例,這裏分享給大家。

目錄:
1、獲取隨機字符串或數字
2、定義一個顏色輸出字符串函數
3、批量創建用戶
4、檢查軟件包是否安裝
5、檢查服務狀態
6、檢查主機存活狀態
7、監控CPU、內存和硬盤利用率
8、批量主機磁盤利用率監控
9、檢查網站可用性
10、檢查MySQL主從同步狀態
11、iptables自動屏蔽訪問網站頻繁的IP
12、判斷用戶輸入的是否爲IP地址
13、判斷用戶輸入的是否爲數字
14、給定目錄找出包含關鍵字的文件
15、監控目錄,將新創建的文件名追加到日誌中
16、給用戶提供多個網卡選擇
17、查看網卡實時流量
18、MySQL數據庫備份
19、Nginx服務管理腳本
20、用戶根據菜單選擇要連接的Linux主機
21、從FTP服務器下載文件
22、連續輸入5個100以內的數字,統計和、最小和最大
23、將結果分別賦值給變量
24、批量修改文件名
25、統計當前目錄中以.html結尾的文件總大
26、掃描主機端口狀態
27、Expect實現SSH免交互執行命令
28、批量修改服務器用戶密碼
29、打印乘法口訣
30、getopts工具完善腳本命令行參數

開頭加解釋器:#!/bin/bash
語法縮進,使用四個空格;多加註釋說明。
命名建議規則:變量名大寫、局部變量小寫,函數名小寫,名字體現出實際作用。
默認變量是全局的,在函數中變量local指定爲局部變量,避免污染其他作用域。
有兩個命令能幫助我調試腳本:set -e 遇到執行非0時退出腳本,set-x 打印執行過程。
寫腳本一定先測試再到生產上。

1.獲取隨機字符串或數字

方法1:
# echo $RANDOM |md5sum |cut -c 1-8
471b94f2
方法2:
# openssl rand -base64 4
vg3BEg==
方法3:
# cat /proc/sys/kernel/random/uuid |cut -c 1-8
ed9e032c
  1. 獲取隨機8位數字
方法1:
# echo $RANDOM |cksum |cut -c 1-8
23648321
方法2:
# openssl rand -base64 4 |cksum |cut -c 1-8       #cksum:打印CRC效驗和統計字節
38571131
方法3:
# date +%N |cut -c 1-8     
69024815
  1. 定義一個顏色輸出字符串函數
方法1:
function echo_color() {
    if [ $1 == "green" ]; then
        echo -e "\033[32;40m$2\033[0m"
    elif [ $1 == "red" ]; then
        echo -e "\033[31;40m$2\033[0m"
    fi
}
方法2:
function echo_color() {
    case $1 in
        green)
            echo -e "[32;40m$2[0m"
            ;;
        red)
            echo -e "[31;40m$2[0m" 
            ;;
        *) 
            echo "Example: echo_color red string"
    esac
}


使用方法:echo_color green "test"
function關鍵字定義一個函數,可加或不加。

3、批量創建用戶

#!/bin/bash
DATE=$(date +%F_%T)
USER_FILE=user.txt
echo_color(){
    if [ $1 == "green" ]; then
        echo -e "[32;40m$2[0m"
    elif [ $1 == "red" ]; then
        echo -e "[31;40m$2[0m"
    fi
}
# 如果用戶文件存在並且大小大於0就備份
if [ -s $USER_FILE ]; then
    mv $USER_FILE ${USER_FILE}-${DATE}.bak
    echo_color green "$USER_FILE exist, rename ${USER_FILE}-${DATE}.bak"
fi
echo -e "User	Password" >> $USER_FILE
echo "----------------" >> $USER_FILE
for USER in user{1..10}; 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 -e "$USER	$PASS" >> $USER_FILE
        echo "$USER User create successful."
    else
        echo_color red "$USER User already exists!"
    fi
done
  1. 檢查軟件包是否安裝
#!/bin/bash
if rpm -q sysstat &>/dev/null; then
    echo "sysstat is already installed."
else
    echo "sysstat is not installed!"
fi

6、檢查主機存活狀態

方法1:將錯誤IP放到數組裏面判斷是否ping失敗三次
#!/bin/bash  
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
for IP in $IP_LIST; do
    NUM=1
    while [ $NUM -le 3 ]; do
        if ping -c 1 $IP > /dev/null; then
            echo "$IP Ping is successful."
            break
        else
            # echo "$IP Ping is failure $NUM"
            FAIL_COUNT[$NUM]=$IP
            let NUM++
        fi
    done
    if [ ${#FAIL_COUNT[*]} -eq 3 ];then
        echo "${FAIL_COUNT[1]} Ping is failure!"
        unset FAIL_COUNT[*]
    fi
done


方法2:將錯誤次數放到FAIL_COUNT變量裏面判斷是否ping失敗三次


#!/bin/bash  
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
for IP in $IP_LIST; do
    FAIL_COUNT=0
    for ((i=1;i<=3;i++)); do
        if ping -c 1 $IP >/dev/null; then
            echo "$IP Ping is successful."
            break
        else
            # echo "$IP Ping is failure $i"
            let FAIL_COUNT++
        fi
    done
    if [ $FAIL_COUNT -eq 3 ]; then
        echo "$IP Ping is failure!"
    fi
done


方法3:利用for循環將ping通就跳出循環繼續,如果不跳出就會走到打印ping失敗
#!/bin/bash
ping_success_status() {
    if ping -c 1 $IP >/dev/null; then
        echo "$IP Ping is successful."
        continue
    fi
}
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
for IP in $IP_LIST; do
    ping_success_status
    ping_success_status
    ping_success_status
    echo "$IP Ping is failure!"
done

7、監控CPU、內存和硬盤利用率

1)CPU
藉助vmstat工具來分析CPU統計信息。
#!/bin/bash
DATE=$(date +%F" "%H:%M)
IP=$(ifconfig eth0 |awk -F  [ :]+   /inet addr/{print $4} )  # 只支持CentOS6
MAIL="[email protected]"
if ! which vmstat &>/dev/null; then
    echo "vmstat command no found, Please install procps package." 
    exit 1
fi
US=$(vmstat |awk  NR==3{print $13} )
SY=$(vmstat |awk  NR==3{print $14} )
IDLE=$(vmstat |awk  NR==3{print $15} )
WAIT=$(vmstat |awk  NR==3{print $16} )
USE=$(($US+$SY))
if [ $USE -ge 50 ]; then
    echo "
    Date: $DATE
    Host: $IP
    Problem: CPU utilization $USE
    " | mail -s "CPU Monitor" $MAIL
fi

2)內存

#!/bin/bash
DATE=$(date +%F" "%H:%M)
IP=$(ifconfig eth0 |awk -F  [ :]+   /inet addr/{print $4} )  
MAIL="[email protected]"
TOTAL=$(free -m |awk  /Mem/{print $2} )
USE=$(free -m |awk  /Mem/{print $3-$6-$7} )
FREE=$(($TOTAL-$USE))
# 內存小於1G發送報警郵件
if [ $FREE -lt 1024 ]; then
    echo "
    Date: $DATE
    Host: $IP
    Problem: Total=$TOTAL,Use=$USE,Free=$FREE
    " | mail -s "Memory Monitor" $MAIL
fi

3)硬盤
#!/bin/bash
DATE=$(date +%F" "%H:%M)
IP=$(ifconfig eth0 |awk -F  [ :]+   /inet addr/{print $4} )  
MAIL="[email protected]"
TOTAL=$(fdisk -l |awk -F [: ]+   BEGIN{OFS="="}/^Disk /dev/{printf "%s=%sG,",$2,$3} )
PART_USE=$(df -h |awk  BEGIN{OFS="="}/^/dev/{print $1,int($5),$6} )
for i in $PART_USE; do
    PART=$(echo $i |cut -d"=" -f1)
    USE=$(echo $i |cut -d"=" -f2)
    MOUNT=$(echo $i |cut -d"=" -f3)
    if [ $USE -gt 80 ]; then
        echo "
        Date: $DATE
        Host: $IP
        Total: $TOTAL
        Problem: $PART=$USE($MOUNT)
        " | mail -s "Disk Monitor" $MAIL
    fi
done




8、批量主機磁盤利用率監控

前提監控端和被監控端SSH免交互登錄或者密鑰登錄。
寫一個配置文件保存被監控主機SSH連接信息,文件內容格式:IP User Port

#!/bin/bash
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)
    TMP_FILE=/tmp/disk.tmp
    ssh -p $PORT $USER@$IP  df -h  > $TMP_FILE
    USE_RATE_LIST=$(awk  BEGIN{OFS="="}/^/dev/{print $1,int($5)}  $TMP_FILE)
    for USE_RATE in $USE_RATE_LIST; do
        PART_NAME=${USE_RATE%=*}
        USE_RATE=${USE_RATE#*=}
        if [ $USE_RATE -ge 80 ]; then
            echo "Warning: $PART_NAME Partition usage $USE_RATE%!"
        fi
    done
done

9、檢查網站可用性

1)檢查URL可用性

方法1:
check_url() {
    HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $1)
    if [ $HTTP_CODE -ne 200 ]; then
        echo "Warning: $1 Access failure!"
    fi
}
方法2:
check_url() {
if ! wget -T 10 --tries=1 --spider $1 >/dev/null 2>&1; then  
#-T超時時間,--tries嘗試1次,--spider爬蟲模式
        echo "Warning: $1 Access failure!"
    fi
}

使用方法:check_url www.baidu.com

2)判斷三次URL可用性
思路與上面檢查主機存活狀態一樣。
方法1:利用循環技巧,如果成功就跳出當前循環,否則執行到最後一行

#!/bin/bash  
check_url() {
    HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $1)
    if [ $HTTP_CODE -eq 200 ]; then
        continue
    fi
}
URL_LIST="www.baidu.com www.agasgf.com"
for URL in $URL_LIST; do
    check_url $URL
    check_url $URL
    check_url $URL
    echo "Warning: $URL Access failure!"
done

方法2:錯誤次數保存到變量

#!/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 -ne 200 ]; then
            let FAIL_COUNT++
        else
            break
        fi
    done
    if [ $FAIL_COUNT -eq 3 ]; then
        echo "Warning: $URL Access failure!"
    fi
done

方法3:錯誤次數保存到數組

#!/bin/bash  
URL_LIST="www.baidu.com www.agasgf.com"
for URL in $URL_LIST; do
    NUM=1
    while [ $NUM -le 3 ]; do
        HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)
        if [ $HTTP_CODE -ne 200 ]; then
            FAIL_COUNT[$NUM]=$IP  #創建數組,以$NUM下標,$IP元素
            let NUM++
        else
            break
        fi
    done
    if [ ${#FAIL_COUNT[*]} -eq 3 ]; then
        echo "Warning: $URL Access failure!"
        unset FAIL_COUNT[*]    #清空數組
    fi
done


10、檢查MySQL主從同步狀態


#!/bin/bash  
USER=bak
PASSWD=123456
IO_SQL_STATUS=$(mysql -u$USER -p$PASSWD -e  show slave statusG  |awk -F:  /Slave_.*_Running/{gsub(": ",":");print $0} )  #gsub去除冒號後面的空格
for i in $IO_SQL_STATUS; do
    THREAD_STATUS_NAME=${i%:*}
    THREAD_STATUS=${i#*:}
    if [ "$THREAD_STATUS" != "Yes" ]; then
        echo "Error: MySQL Master-Slave $THREAD_STATUS_NAME status is $THREAD_STATUS!"
    fi
done

11、iptables自動屏蔽訪問網站頻繁的IP
場景:惡意訪問,安全防範

1)屏蔽每分鐘訪問超過200的IP
方法1:根據訪問日誌(Nginx爲例)
#!/bin/bash
DATE=$(date +%d/%b/%Y:%H:%M)
ABNORMAL_IP=$(tail -n5000 access.log |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>100)print i}')
#先tail防止文件過大,讀取慢,數字可調整每分鐘最大的訪問量。awk不能直接過濾日誌,因爲包含特殊字符。
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -I INPUT -s $IP -j DROP
    fi
done

方法2:通過TCP建立的連接

#!/bin/bash
ABNORMAL_IP=$(netstat -an |awk '$4~/:80$/ && $6~/ESTABLISHED/{gsub(/:[0-9]+/,"",$5);{a[$5]++}}END{for(i in a)if(a[i]>100)print i}')
#gsub是將第五列(客戶端IP)的冒號和端口去掉
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -I INPUT -s $IP -j DROP
    fi
done

2)屏蔽每分鐘SSH嘗試登錄超過10次的IP

方法1:通過lastb獲取登錄狀態:
#!/bin/bash
DATE=$(date +"%a %b %e %H:%M") #星期月天時分  %e單數字時顯示7,而%d顯示07
ABNORMAL_IP=$(lastb |grep "$DATE" |awk '{a[$3]++}END{for(i in a)if(a[i]>10)print i}')
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -I INPUT -s $IP -j DROP
    fi
done


方法2:通過日誌獲取登錄狀態

#!/bin/bash
DATE=$(date +"%b %d %H")
ABNORMAL_IP="$(tail -n10000 /var/log/auth.log |grep "$DATE" |awk '/Failed/{a[$(NF-3)]++}END{for(i in a)if(a[i]>5)print i}')"
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -A INPUT -s $IP -j DROP
        echo "$(date +"%F %T") - iptables -A INPUT -s $IP -j DROP" >>~/ssh-login-limit.log
    fi
done

12、判斷用戶輸入的是否爲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



13、判斷用戶輸入的是否爲數字

方法1:
#!/bin/bash
if [[ $1 =~ ^[0-9]+$ ]]; then
    echo "Is Number."
else
    echo "No Number."
fi

方法2:
#!/bin/bash
if [ $1 -gt 0 ] 2>/dev/null; then
    echo "Is Number."
else
    echo "No Number."
fi

方法3:

#!/bin/bash
echo $1 |awk '{print $0~/^[0-9]+$/?"Is Number.":"No Number."}'  #三目運算符
12.14 找出包含關鍵字的文件
DIR=$1
KEY=$2
for FILE in $(find $DIR -type f); do
    if grep $KEY $FILE &>/dev/null; then
        echo "--> $FILE"
    fi
done

14、給定目錄找出包含關鍵字的文件

#!/bin/bash
DIR=$1
KEY=$2
for FILE in $(find $DIR -type f); do
    if grep $KEY $FILE &>/dev/null; then
        echo "--> $FILE"
    fi
done

15、監控目錄,將新創建的文件名追加到日誌中

場景:記錄目錄下文件操作。
需先安裝inotify-tools軟件包。

#!/bin/bash
MON_DIR=/opt
inotifywait -mq --format %f -e create $MON_DIR |\
while read files; do
  echo $files >> test.log
done

16、給用戶提供多個網卡選擇

場景:服務器多個網卡時,獲取指定網卡,例如網卡流量

#!/bin/bash
function local_nic() {
    local NUM ARRAY_LENGTH
    NUM=0
    for NIC_NAME in $(ls /sys/class/net|grep -vE "lo|docker0"); do
        NIC_IP=$(ifconfig $NIC_NAME |awk -F'[: ]+' '/inet addr/{print $4}')
        if [ -n "$NIC_IP" ]; then
            NIC_IP_ARRAY[$NUM]="$NIC_NAME:$NIC_IP"    #將網卡名和對應IP放到數組
            let NUM++
        fi
    done
    ARRAY_LENGTH=${#NIC_IP_ARRAY[*]}
    if [ $ARRAY_LENGTH -eq 1 ]; then     #如果數組裏面只有一條記錄說明就一個網卡
        NIC=${NIC_IP_ARRAY[0]%:*}
        return 0
    elif [ $ARRAY_LENGTH -eq 0 ]; then   #如果沒有記錄說明沒有網卡
        echo "No available network card!"
        exit 1
    else
        #如果有多條記錄則提醒輸入選擇
        for NIC in ${NIC_IP_ARRAY[*]}; do
            echo $NIC
        done
        while true; do
            read -p "Please enter local use to network card name: " INPUT_NIC_NAME
            COUNT=0
            for NIC in ${NIC_IP_ARRAY[*]}; do
                NIC_NAME=${NIC%:*}
                if [ $NIC_NAME == "$INPUT_NIC_NAME" ]; then
                    NIC=${NIC_IP_ARRAY[$COUNT]%:*}
                    return 0
                else
                   COUNT+=1
                fi
            done
            echo "Not match! Please input again."
        done
    fi
}
local_nic

17、查看網卡實時流量
適用於CentOS6操作系統。

#!/bin/bash
# Description: Only CentOS6
traffic_unit_conv() {
    local traffic=$1
    if [ $traffic -gt 1024000 ]; then
        printf "%.1f%s" "$(($traffic/1024/1024))" "MB/s"
    elif [ $traffic -lt 1024000 ]; then
        printf "%.1f%s" "$(($traffic/1024))" "KB/s"
    fi
}
NIC=$1
echo -e " In ------ Out"
while true; do
    OLD_IN=$(awk -F'[: ]+' '$0~"'$NIC'"{print $3}' /proc/net/dev)
    OLD_OUT=$(awk -F'[: ]+' '$0~"'$NIC'"{print $11}' /proc/net/dev)
    sleep 1
    NEW_IN=$(awk -F'[: ]+' '$0~"'$NIC'"{print $3}' /proc/net/dev)
    NEW_OUT=$(awk -F'[: ]+' '$0~"'$NIC'"{print $11}' /proc/net/dev)
    IN=$(($NEW_IN-$OLD_IN))
    OUT=$(($NEW_OUT-$OLD_OUT))
    echo "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)"
    sleep 1
done
使用:./traffic.sh eth0

18、MySQL數據庫備份

#!/bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=192.168.1.120
DB=test
USER=bak
PASS=123456
MAIL="[email protected] [email protected]"
BACKUP_DIR=/data/db_backup
SQL_FILE=${DB}_full_$DATE.sql
BAK_FILE=${DB}_full_$DATE.zip
cd $BACKUP_DIR
if mysqldump -h$HOST -u$USER -p$PASS --single-transaction --routines --triggers -B $DB > $SQL_FILE; then
    zip $BAK_FILE $SQL_FILE && rm -f $SQL_FILE
    if [ ! -s $BAK_FILE ]; then
            echo "$DATE 內容" | mail -s "主題" $MAIL
    fi
else
    echo "$DATE 內容" | mail -s "主題" $MAIL
fi
find $BACKUP_DIR -name '*.zip' -ctime +14 -exec rm {} \;

19、Nginx服務管理腳本

場景:使用源碼包安裝Nginx不含帶服務管理腳本,也就是不能使用"service nginx start""/etc/init.d/nginx start",所以寫了以下的服務管理腳本。

#!/bin/bash
# Description: Only support RedHat system
. /etc/init.d/functions
WORD_DIR=/usr/local/nginx
DAEMON=$WORD_DIR/sbin/nginx
CONF=$WORD_DIR/conf/nginx.conf
NAME=nginx
PID=$(awk -F'[; ]+' '/^[^#]/{if($0~/pid;/)print $2}' $CONF)
if [ -z "$PID" ]; then
    PID=$WORD_DIR/logs/nginx.pid
else
    PID=$WORD_DIR/$PID
fi
stop() {
    $DAEMON -s stop
    sleep 1
    [ ! -f $PID ] && action "* Stopping $NAME"  /bin/true || action "* Stopping $NAME" /bin/false
}
start() {
    $DAEMON
    sleep 1
    [ -f $PID ] && action "* Starting $NAME"  /bin/true || action "* Starting $NAME" /bin/false
}
reload() {
    $DAEMON -s reload
}
test_config() {
    $DAEMON -t
}
case "$1" in
    start)
        if [ ! -f $PID ]; then
            start
        else
            echo "$NAME is running..."
            exit 0
        fi
        ;;
    stop)
        if [ -f $PID ]; then
            stop
        else
            echo "$NAME not running!"
            exit 0
        fi
        ;;
    restart)
        if [ ! -f $PID ]; then
            echo "$NAME not running!" 
            start
        else
            stop
            start
        fi
        ;;
    reload)
        reload
        ;;
    testconfig)
        test_config
        ;;
    status)
        [ -f $PID ] && echo "$NAME is running..." || echo "$NAME not running!"
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|reload|testconfig|status}"
        exit 3
        ;;
esac



20、用戶根據菜單選擇要連接的Linux主機

Linux主機SSH連接信息:
# cat host.txt
Web 192.168.1.10 root 22
DB 192.168.1.11 root 22

內容格式:主機名 IP User Port

#!/bin/bash
PS3="Please input number: "
HOST_FILE=host.txt
while true; do
    select NAME in $(awk '{print $1}' $HOST_FILE) quit; do
        [ ${NAME:=empty} == "quit" ] && exit 0
        IP=$(awk -v NAME=${NAME} '$1==NAME{print $2}' $HOST_FILE)
        USER=$(awk -v NAME=${NAME} '$1==NAME{print $3}' $HOST_FILE)
        PORT=$(awk -v NAME=${NAME} '$1==NAME{print $4}' $HOST_FILE)
        if [ $IP ]; then
            echo "Name: $NAME, IP: $IP"
            ssh -o StrictHostKeyChecking=no -p $PORT -i id_rsa $USER@$IP  # 密鑰免交互登錄
            break
        else
            echo "Input error, Please enter again!"
            break
        fi
    done
done

21、從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

22、連續輸入5個100以內的數字,統計和、最小和最大

#!/bin/bash
COUNT=1
SUM=0
MIN=0
MAX=100
while [ $COUNT -le 5 ]; do
    read -p "請輸入1-10個整數:" INT
    if [[ ! $INT =~ ^[0-9]+$ ]]; then
        echo "輸入必須是整數!"
        exit 1
    elif [[ $INT -gt 100 ]]; then
        echo "輸入必須是100以內!"
        exit 1
    fi
    SUM=$(($SUM+$INT))
    [ $MIN -lt $INT ] && MIN=$INT
    [ $MAX -gt $INT ] && MAX=$INT
    let COUNT++
done
echo "SUM: $SUM"
echo "MIN: $MIN"
echo "MAX: $MAX"

23、將結果分別賦值給變量
應用場景:希望將執行結果或者位置參數賦值給變量,以便後續使用。

方法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]})

24、批量修改文件名

示例:
# touch article_{1..3}.html
# ls
article_1.html  article_2.html  article_3.html

目的:把article改爲bbs

方法1:
for file in $(ls *html); do
    mv $file bbs_${file#*_}
    # mv $file $(echo $file |sed -r 's/.*(_.*)/bbs\1/')
    # mv $file $(echo $file |echo bbs_$(cut -d_ -f2)
done

方法2:
for file in $(find . -maxdepth 1 -name "*html"); do
     mv $file bbs_${file#*_}
done


方法3:
# rename article bbs *.html


25、統計當前目錄中以.html結尾的文件總大

方法1:

# find . -name "*.html" -exec du -k {} \; |awk '{sum+=$1}END{print sum}'

方法2:

for size in $(ls -l *.html |awk '{print $5}'); do
    sum=$(($sum+$size))
done
echo $sum

26、掃描主機端口狀態

#!/bin/bash
HOST=$1
PORT="22 25 80 8080"
for PORT in $PORT; do
    if echo &>/dev/null > /dev/tcp/$HOST/$PORT; then
        echo "$PORT open"
    else
        echo "$PORT close"
    fi
done

27、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

28、批量修改服務器用戶密碼

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遠程修改密碼腳本:新密碼隨機生成

#!/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


29、打印乘法口訣

方法1:
# awk 'BEGIN{for(n=0;n++<9;){for(i=0;i++<n;)printf i"x"n"="i*n" ";print ""}}'

方法2:


for ((i=1;i<=9;i++)); do
   for ((j=1;j<=i;j++)); do
     result=$(($i*$j))
     echo -n "$j*$i=$result "
   done
   echo
done

30、getopts工具完善腳本命令行參數

getopts是一個解析腳本選項參數的工具。
命令格式:getopts optstring name [arg]
初次使用你要注意這幾點:
腳本位置參數會與optstring中的單個字母逐個匹配,如果匹配到就賦值給name,否則賦值name爲問號;
optstring中單個字母是一個選項,如果字母后面加冒號,表示該選項後面帶參數,參數值並會賦值給OPTARG變量;
optstring中第一個是冒號,表示屏蔽系統錯誤(test.sh: illegal option -- h);
允許把選項放一起,例如-ab

下面寫一個打印文件指定行的簡單例子,引導你思路:
#!/bin/bash
while getopts :f:n: option; do
    case $option in
        f)
            FILE=$OPTARG
      [ ! -f $FILE ] && echo "$FILE File not exist!" && exit
            ;;
        n)
            sed -n "${OPTARG}p" $FILE
            ;;
        ?)
            echo "Usage: $0 -f <file_path> -n <line_number>"
            echo "-f, --file           specified file"
            echo "-n, --line-number    print specified line"
            exit 1
        ;;
    esac
done




這裏的腳本是根據李振良老師的《DevOps技術棧》中學習到的,感謝李振良老師。

這是入口

Kubernetes技術交流羣:901304910
Python運維開發交流羣:249171211

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章