1. 程式人生 > >30個關於Shell指令碼的經典案例(下)

30個關於Shell指令碼的經典案例(下)

本文目錄

21、從FTP伺服器下載檔案
22、連續輸入5個100以內的數字,統計和、最小和最大
23、將結果分別賦值給變數
24、批量修改檔名
25、統計當前目錄中以.html結尾的檔案總大
26、掃描主機埠狀態
27、Expect實現SSH免互動執行命令
28、批量修改伺服器使用者密碼
29、列印乘法口訣
30、getopts工具完善指令碼命令行引數

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"
30個關於Shell指令碼的經典案例(下)30個關於Shell指令碼的經典案例(下)

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
生成新密碼檔案:
https://www.linuxprobe.com/books
# 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  -n "
            echo "-f, --file           specified file"
            echo "-n, --line-number    print specified line"
            exit 1
        ;;
    esac
done
30個關於Shell指令碼的經典案例(下)30個關於Shell指令碼的經典案例(下)

根據工作經驗總結的30個Shell指令碼案例至此完結,都還是比較實用的,面試筆試題也經常會出。希望朋友們多動手練一練,讓你的Shell功底