首先,對於運維行業,不管是雲計算運維還是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
- 獲取隨機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:
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
- 檢查軟件包是否安裝
#!/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