bash基礎(chǔ)及shell腳本編程初步

2016年12月15日09:42:35 3 5,882 ℃

終端,附著在終端的接口程序

GUI:KDE,GNome ,Xfce

CLI : /etc/shells

bash

zsh

fish

bash的特性:

命令行展開: ~,{}

命令別名: alias, unalias

命令歷史: history

文件名通配:glob

快捷鍵:Ctrl+a,e , u , k ,l

命令補(bǔ)全: $PATH

路徑補(bǔ)全:

bash特性之:命令hash

緩存此前命令的查找結(jié)果:key-value

key:搜索鍵

value: 值

hash命令:

hash:列出

hash -d COMMAND:刪除

hash -r :清空

bash的特性之:變量

程序:指令+數(shù)據(jù)

指令:由程序文件提供

數(shù)據(jù):IO設(shè)備、文件、管道、變量

程序:算法+數(shù)據(jù)結(jié)構(gòu)

變量名+指向的內(nèi)存空間

變量賦值:name=value

變量類型:存儲(chǔ)格式、表示數(shù)據(jù)范圍、參與的運(yùn)算

編程語言:

強(qiáng)類型變量:

弱類型變量:

bash把所有變量統(tǒng)統(tǒng)視作字符型; 

bash中的變量無需事先聲明;相當(dāng)于,把聲明和復(fù)制過程同時(shí)實(shí)現(xiàn)

聲明:類型,變量名

變量替換:把變量名出現(xiàn)的位置替換為其所指向的內(nèi)存空間中的數(shù)據(jù)

變量引用: ${var_name} ,$var_name

變量名:變量名只能包含數(shù)字、字母和下劃線,而且不能以數(shù)字開頭,不能使用程序的保留字段:if while for then

變量:見名知義,命名機(jī)制遵循某種法則

bash變量類型:

本地變量:作用域僅為當(dāng)前shell進(jìn)程

環(huán)境變量:作用域僅為當(dāng)前shell進(jìn)程及其子進(jìn)程

局部變量:作用域僅為代碼片段(函數(shù)上下文)

位置參數(shù)變量:當(dāng)執(zhí)行腳本的shell進(jìn)程傳遞的參數(shù)

$1,$2...

shift

特殊變量:shell內(nèi)置的有特殊功能的變量

$?:上一個(gè)命令的執(zhí)行狀態(tài)返回值

0:成功

1-255:失敗

$#:參數(shù)的個(gè)數(shù)

$*:參數(shù)列表

$@: 參數(shù)列表

本地變量:

變量賦值:name=value

變量引用:${name}, $name

"":變量為會(huì)替換為其值

'':變量名不會(huì)替換為其值

查看變量:set

撤銷變量:unset name

注意:此處非變量引用

環(huán)境變量:

變量賦值:

(1)export name=value

(2)name=value
         export name

(3)declare -x name=value

(4)name=value

declare -x name

變量引用:${name}, $name

注意:bash內(nèi)嵌了許多環(huán)境變量(通常為全大寫字符),用于定義bash的工作環(huán)境

PATH ,HISTFILE, HISTSIZE, HISTFILESIZE,HISTCONTROL, SHELL ,HOME ,UID ,PWD ,OLDPWD

查看環(huán)境變量:export ,declare -x, printenv ,env

撤銷環(huán)境變量:unset name

只讀變量:

(1)declare -r name

(2)readonly name

只讀變量無法重新賦值,并且不支持撤銷;存活時(shí)間為當(dāng)前shell進(jìn)程的生命周期,隨shell進(jìn)程終止而終止

bash特性之多命令執(zhí)行:

COMMAND1; COMMAND2; COMMAND3; ....

邏輯運(yùn)算:

真(true, yes, on ,1)

假(false, no , off , 0)

與:

1&&1=1

1&&0=0

0&&1=0

0&&0=0

或:

1 || 1=1

1 || 0=1

0 || 1=1

0 || 0=0

非:

!1=0

!0=1

短路法則:

COMMAND1 && COMMAND2

COMMAND1為“假”,則COMMAND2不會(huì)再執(zhí)行

否則,COMMAND1為“真”,則COMMAND2必須執(zhí)行

COMMAND1 || COMMAND2
COMMAND1為“真”,則COMMAND2不會(huì)再執(zhí)行
否則,COMMAND1為“假”,則COMMAND2必須執(zhí)行

例:id $username || useradd $useradd

練習(xí)1:

1、添加3個(gè)用戶user1,user2,user3,先判斷用戶是否存在,不存在而后再添加

2、顯示當(dāng)前系統(tǒng)上共有多少個(gè)用戶

#!/bin/bash
for i in user1 user2 user3
do
! id $i &> /dev/null  && useradd $i && echo $i | passwd --stdin $i &> /dev/null || echo "$i is exists"
done
sum=`wc -l /etc/passwd | cut -d' ' -f1`
echo "$sum /etc/passwd users"

shell腳本編程:

編程語言的分類:根據(jù)運(yùn)行方式

編譯運(yùn)行:源代碼-->編譯器(編譯)-->程序文件

解釋運(yùn)行:源代碼-->運(yùn)行時(shí)啟動(dòng)解釋器,由解釋器邊解釋邊運(yùn)行

根據(jù)其編程過程中功能的實(shí)現(xiàn)是調(diào)用庫還是調(diào)用外部的程序文件:

shell腳本編程:

利用系統(tǒng)上的命令及編程組件進(jìn)行編程

完整編程:

利用庫和編程組件進(jìn)行編程

編程模型:過程式編程語言,面向?qū)ο蟮木幊陶Z言

程序+指令+數(shù)據(jù)

過程式:以指令為中心來組織代碼,數(shù)據(jù)是服務(wù)于代碼;

順序執(zhí)行:

選擇執(zhí)行:

循環(huán)執(zhí)行:

代表:c語言,bash

對象式:以數(shù)據(jù)為中心來組織代碼,圍繞數(shù)據(jù)來組織指令;

類(class):實(shí)例化對象,method:

代表:java,c++, python

shell腳本編程:過程式編程,解釋運(yùn)行,依賴于外部程序程序文件運(yùn)行;

如何寫shell腳本:

腳本文件的第一行,頂格:給出shebang, 解析器路徑,用于指明解析執(zhí)行當(dāng)前腳本解析器程序文件

常見的解析器:

#!/bin/bash

#!/usr/bin/python

#!/usr/bin/perl

文本編輯器:nano

行編輯器:sed

全屏幕編程器:nano, vi , vim

shell腳本是什么?

命令的堆積:

但很多命令不具有冪等性,需要用程序邏輯來判斷運(yùn)行條件十分滿足,以避免其運(yùn)行中發(fā)生錯(cuò)誤;

運(yùn)行腳本:

(1)賦予執(zhí)行權(quán)限,并直接運(yùn)行此程序文件;

chmod +x /path/to/script_file

/path/to/script_file

(2)直接運(yùn)行解析器,將腳本以命令行參數(shù)傳遞給解釋器程序

bash/path/to/script_file

注意:腳本中的空白行會(huì)被解釋器忽略

腳本中,除了shebang,余下所有#開頭的行,都會(huì)被視作注釋而被忽略;此即為注釋行

shell腳本的運(yùn)行是通過運(yùn)行一個(gè)子shell進(jìn)程實(shí)現(xiàn)的

練習(xí)1:寫一個(gè)腳本,實(shí)現(xiàn)如下功能:

(1)顯示/etc目錄下所有以大寫P或小寫p開頭的文件或目錄本身

(2)顯示/var目錄下所有文件或者目錄本身,并將顯示結(jié)果中的小寫字母轉(zhuǎn)換為大寫顯示

(3)創(chuàng)建臨時(shí)文件/tmp/myfile.XXXX

bash的配置文件:

兩類:

profile類:為交互式登錄的shell提供配置

bashrc類:為非交互式登錄的shell提供配置

登錄類型:

交互式登錄shell進(jìn)程:

直接通過某終端輸入賬號和密碼后登錄打開的shell進(jìn)程;

使用su命令:su -username,或者使用su -l username執(zhí)行的登錄切換。

非交互式登錄shell進(jìn)程:

su username執(zhí)行的登錄切換;

圖形界面下打開的終端

profile類:

全局:對所有用戶都生效:

/etc/profile

/etc/profid.d/*.sh

用戶個(gè)人:僅對當(dāng)前用戶有效;

~/.bash_profile

功用:

1、用戶定義環(huán)境變量

2、運(yùn)行命令或腳本

bashrc類:

全局:

/etc/bashrc

用戶個(gè)人:

~/.bashrc

功用:

1、定義本地變量:

2、定義命令別名:

注意:僅管理員可修改全局配置文件

交互式登錄shell進(jìn)程:

/etc/profile-->/etc/profile.d/*-->/.bash_profile-->~/.bashrc-->/etc/bashrc

非交互式登錄shell進(jìn)程:

~/.bashrc-->/etc/bashrc-->/etc/profile.d/*

命令行中定義的特性,例如變量和別名作用域?yàn)楫?dāng)前shell進(jìn)程的生命周期

配置文件定義的特性,只對隨后新啟動(dòng)的shell進(jìn)程有效;

讓通過配置文件定義的特性立即生效:

(1)通過命令行中重復(fù)定義一次;

(2)讓shell進(jìn)程重讀配置文件;

source /path/from/conf_file

. /path/from/conf_file

問題1:定義對所有用戶都生效的命令別名,例如“l(fā)ftps=lftp 172.16.1.110/pub”?

問題2:讓centos用戶登錄時(shí),提示其已經(jīng)登錄,并提示當(dāng)前時(shí)間。

vim /etc/profile.d//welcome.sh

echo "Welcome login!"

echo -n "NOW Time is: " 

date

echo -n "Login ip:"

who | awk 'END{print $5}' |tr "()" " "

bash的算術(shù)運(yùn)算

+ ,- ,*,/ ,** ,%

取模,取余%

3%2=1

100%55=45

算術(shù)運(yùn)算格式

(1)let VAR=算術(shù)運(yùn)算表達(dá)式

(2)VAR=$[算術(shù)運(yùn)算表達(dá)式]

(3)VAR=$((算術(shù)運(yùn)行表達(dá)式))

(4)VAR=$(expr $ARG1 $OP $ARG2)

注意:乘法符號在有些場景中需要使用轉(zhuǎn)義符

練習(xí):寫一個(gè)腳本,完成如下功能;添加三個(gè)用戶;求此三個(gè)用戶的UID之和

#i/usr/bash

for((i=1;i<=3;i++));do

username="user$i"

useradd "$username"

echo "$username" | passwd --stdin $username

num=$(id -u "$username")

let sum=sum+$num

done

echo $sum

條件判斷

bash中如何實(shí)現(xiàn)條件判斷?

條件測試類型

整數(shù)測試

字符測試

文件測試

條件測試的表達(dá)式

[ expression ]

[[ expression ]]

test expression

整數(shù)比較:

-eq:測試兩個(gè)整數(shù)是否相等:比如$a -eq $b

-ne:測試兩個(gè)整數(shù)是否不等:不等,為真:相等,為假

-gt:測試一個(gè)數(shù)是否大于另一個(gè)數(shù):大于,為真;否則,為假

-lt:測試一個(gè)數(shù)是否小于另一個(gè)數(shù):小于,為真;否則,為假

-ge:大于或等于

-le:小于或等于

練習(xí):

1.判斷當(dāng)前系統(tǒng)上是否有用戶的默認(rèn)shell為bash;如果有,就顯示有多少個(gè)這類用戶;否則,就顯示沒有這類用戶

2.判定命令歷史中歷史命令的總條目是否大于1000;如果大于就顯示“some command will gone”;否則顯示“OK”

num=`history | tail -1 | awk  '{print $1}'`

if [[ $num -gt 1000 ]];then

echo "OK!"

else

echo "Some command will gone"

fi

3.給定一個(gè)用戶,獲取其mime警告期限;而判斷用戶mime使用期限是否已經(jīng)小于警告期限(提示:計(jì)算方法,最長使用期限減去已經(jīng)使用的天數(shù)即為剩余使用期限);如果小于,則顯示“warning”;否則,就顯示“OK”

#!/bin/bash

TODAY=`date +%s`

ZUIJIN=`tail -1 /etc/shadow | cut -d":" -f3`

SHIY ))

ZUICHANG=`tail -1 /etc/shadow | cut -d":" -f5`

JINGAO=`tail -1 /etc/shadow | cut -d":" -f6`

SY=$[ $ZUICHANG-$SHIYONG  ]

if [ $SY -gt $JINGAO ];then

echo "OK!"

else

echo "Warning!"

fi 

文件測試:

-e FILE:測試文件是否存在 存在為true

-f FILE:測試文件是否為普通文件

-d FILE:測試指定路徑是否為目錄

-r FILE:測試當(dāng)前用戶對指定文件是否有讀權(quán)限

-w FILE:

-x FILE:

[ -x /etc/rc.d/rc.sysinit ]

字符串測試:

== 測試是否相等,等為真,不等為假

!=:測試是否不等,不等為真,等為假

>

<

-z sting:測試指定字符串是否為0,0為真,不為0則假

-n string: 測試指定字符串是否為0,不為0為真,0則假

-str string:測試指定字符串是否不空,不空為真,空則假

if []

組合測試:

-a:與關(guān)系

-o:或關(guān)系

!:非關(guān)系

if [ $# -gt 1 -a $# -le 3 ]

if [ $# -gt 1  ]  && [ $# -le 3 ]

測試腳本是否有語法錯(cuò)誤:

bash -n

單步執(zhí)行:

bash -x

練習(xí)

1.給定一個(gè)文件,如果是一個(gè)普通文件,就顯示之;如果是一個(gè)目錄,亦顯示之;否則,此為無法識(shí)別之文件。

#!/bin/bash

FILE=/etc/shadow2

if [ ! -e $FILE ];then

        echo "NO such file."

        exit 1

fi

if [ -e $FILE ];then

        echo "wenjian" 

elif [ -d $FILE ];then

        echo "mulu"

else

        echo "Unknown"

fi

2.給腳本傳遞兩個(gè)參數(shù)(整數(shù));顯示此兩者之和,之積。

#/bin/bash

if [ $# -ne 2  ]; then

echo "Plese Enter Two AGE"

exit 2

fi

HE=$[ $1+$2 ]

JI=$[ $1*$2 ]

echo "$1 + $2=$HE"
echo "$1 * $2=$JI"

練習(xí):

1、傳遞一個(gè)用戶名參數(shù)腳本,判斷此用戶的用戶名跟其基本組的組名是否一致,并將結(jié)果顯示出來

#!/bin/bash

if  ! id $1 &>/dev/null;then

echo "NO such User"

exit 6

fi

G=`id -n -g $1`

if [ $G = $1 ];then

echo "yiyang"

else

echo " buyiyang"

fi

2、傳遞三個(gè)參數(shù)給腳本,第一個(gè)為整數(shù),第二個(gè)為算術(shù)運(yùn)算符,第三個(gè)為整數(shù),將計(jì)算結(jié)果顯示出來,要求保留兩位精度。如: ./calc.sh 5 / 2

#!/bin/bash

echo "scale=2;$1$2$3 "|bc

3、傳遞三個(gè)參數(shù)給腳本,參數(shù)均為用戶名。將此用戶的賬號信息提取出來后放置于/tmp/testusers.txt文件中,并要求每一行行首有行號。

#!/bin/bash

for i in $@;do

if  ! id $i &>/dev/null;then

echo "$i Not User"

exit 6

fi

done

echo "1 $1" | tee -a /tmp/testuser.txt

echo "2 $2" | tee -a /tmp/testuser.txt

echo "3 $3" | tee -a /tmp/testuser.txt

#!/bin/bash

for i in $@;do

if  ! id $i &>/dev/null;then

echo "$i Not User"

exit 6

fi

done

m=1

while (( $m<=$#  ));do

        for i in $@;do

        echo $m $i |tee -a /tmp/testusers.txt

        let "m++"

        done

done

4、寫一個(gè)腳本:

判斷當(dāng)前主機(jī)的CPU生產(chǎn)商,其信息在/proc/cpuinfo文件中vendor id 一行中。

如果其生產(chǎn)商為AuthenticAMD,就顯示為AMD公司

如果其生產(chǎn)商為GenuineIntel,就顯示為Intel公司
否則,就說其為非主流公司

#!/bin/bash

CPU=`grep "vendor_id" /proc/cpuinfo | head -1 | awk '{print $3}'`

if [ $CPU == "AuthenticAMD" ];then

        echo "AMD"

elif [ $CPU == "GenuineIntel" ]

        echo "Intel"

else

        echo "Feizhuliu"

fi   

5、寫一個(gè)腳本:

給腳本傳遞三個(gè)參數(shù),判斷其中 的最大數(shù)和最小數(shù),并顯示出來

#!/bin/bash

MAX=0

for i in $@;do

        if [ $i -gt $MAX ];then

                MAX=$i

        fi

done

        echo Max is $MAX

SMALL=0
NUM=0
for i in $@;do
        let NUM++
        [ $NUM -eq 1 ]&& SMALL=$i
        if [ $i -lt $SMALL ];then
                SMALL=$i
        fi
done
        echo Small is $SMALL

條件判斷,控制結(jié)構(gòu):

單分支if語句

if 判斷條件;then

statement1

statement1

...

fi

雙分支的if語句:

if 判斷條件;then

statement1

statement2

...

else

statement3

statement4

...

fi

多分支if語句:

if 判斷條件;then

statement1

statement2

elif 判斷條件2;then

statement3

statement4

elif 判斷條件3;then

statement5
statement6

else

statement7

fi

case語句

case SWITCH in

value1)

statement

...

;;

value2)

statement

...

;;

*)

statement

...

;;

esac

寫一個(gè)腳本:

只接收參數(shù)start,stop,restrart,status其中之一。

#!/bin/bash

case $1 in

'start')

        echo "start!";;

'stop')

        echo "stop!";;

'restart')

        echo "restart!";;

'staus')

        echo "staus!";;

*)

        echo `basename $0` "(start|stop|restrart|status)"

esac

寫一個(gè)腳本,可以接受選項(xiàng)及參數(shù),而后能獲取每一個(gè)選項(xiàng),及選項(xiàng)的參數(shù);并能根據(jù)選項(xiàng)參數(shù)做出特定的操作,比如:

adminusers.sh --add tom,jerry   --del tom,blair  -v|--verbose -h|--help

#!/bin/bash

DEBUG=0

ADD=0

DEL=0

for i in `seq 0 $#`;do

if [ $# -gt 0 ];then

case $1 in

-v|--verbose)

        DEBUG=1

        shift ;;

-h|--help)

        echo "Usage: `basename $0` --add USER_LIST --del USER_LIST -v|--verbose -h|--help"

        exit 0 ;;

--add)

        ADD=1

        USERS=$2

        shift 2 ;;

--del)

        DEL=1

        USERS=$2

        shift 2 ;;

*)

       echo "Usage: `basename $0` --add USER_LIST --del USER_LIST -v|--verbose -h|--help"

       exit 6 ;;

esac

fi

done

if [ $ADD -eq 1 ];then

        for user in  `echo $USERS | tr "," " "`;do

                if id $user &>/dev/null;then

                         [ $DEBUG -eq 1 ] && echo "$user exists"

                else

                        useradd $user

                        echo $user |  passwd --stdin $user &>/dev/null

                        [ $DEBUG -eq 1 ] && echo "Add user:$user finished! "

                fi

        done

fi

if [ $DEL -eq 1 ];then

        for user in  `echo $USERS | tr "," " "`;do

                if id $user &>/dev/null;then

                         userdel -rf $user &>/dev/null

                         [ $DEBUG -eq 1 ] && echo "$user Delete finished!"

                else

                        [ $DEBUG -eq 1 ] && echo "$user Not exist. "

                fi

        done

fi

練習(xí):寫一個(gè)腳本showlogged.sh,其中語法格式為:

showlogged.sh -v -c -h|--help

其中,-h選項(xiàng)只能單獨(dú)使用,用于顯示幫助信息;-c選項(xiàng)時(shí),顯示當(dāng)前系統(tǒng)上登錄的所有用戶數(shù);如果同時(shí)使用了-v選項(xiàng),則即顯示同時(shí)登錄的用戶數(shù),又顯示登錄的用戶的相關(guān)信息;如:

logged users: 4

they are:

root     pts/0        2016-10-09 12:38 (171.221.140.180)
root     pts/2        2016-10-09 13:15 (171.221.140.180)
root     pts/3        2016-10-09 13:16 (171.221.140.180)

#!/bin/bash

declare -i DEBUG=0

declare -i USER=0

for i in `seq 1 $#`;do

if [ $# -gt 0 ];then

case $1 in

-v)

        DEBUG=1

        shift;;

-h|--help)

        echo "Usage:`basename $0` -v -c -h|--help"

        exit 0;;

-c)

        USER=1

        shift ;;

*)

        echo "Usage:`basename $0` -v -c -h|--help"

        exit 7;;

esac

fi

done

if [ $USER -eq 1  ];then

        num=`who | wc -l`

        echo "Logged users:$num"

        if [ $DEBUG -eq 1 ];then

                echo "They are:" 

                who

        fi

fi

循環(huán):進(jìn)入條件,退出條件 

for循環(huán)格式:

for varaible in list ;do

循環(huán)體

done

for ((expr1;expr2;expr3));do

循環(huán)體

done

如何生成列表:

{1..100}

`seq [起始數(shù) [步進(jìn)長度] ] 結(jié)束數(shù)`

聲明變量 declare -i sum=0

integer

-x 環(huán)境變量

#!/bin/bash

sum=0

for i in {1..100};do

        let sum=$sum+$i

done

echo $sum

練習(xí):寫一個(gè)腳本

(1、設(shè)定變量FILE的值為/etc/passwd

(2、依次向/etc/passwd中的每個(gè)用戶問好,并顯示對方的shell,如:Hello, root ,your shell: /bin/bash

(3、統(tǒng)計(jì)一共有多少個(gè)用戶

#!/bin/bash

LIST=`awk -F: '{print $1}' /etc/passwd`

for i in $LIST;do

        BS=`grep "^$i\>" /etc/passwd | awk -F: '{print $7}'`

        echo "Hello,$i  Your bash is $BS"

done

sum=`wc -l /etc/passwd | cut -d' ' -f1`
echo "$sum /etc/passwd users"

2、寫一個(gè)腳本

添加10個(gè)用戶user1到user10,但要求只有用戶不存在的情況下才添加

#!/bin/bash

for m in {1..10};do

i=user$m

! id $i &> /dev/null  && useradd $i && echo $i | passwd --stdin $i &> /dev/null || echo "$i is exists"

done

擴(kuò)展:

接收一個(gè)參數(shù):

add:添加user1-user10

del:刪除user1-user10

其他:退出

#!/bin/bash
if [[ $1 != add && $1 != del ]];then
        echo "Plese ENter add OR del"
        echo "exit..."
        exit 6
fi
for i in {1..10};do
        NAME=user$i
        if  [[ $1 == add  ]];then
                useradd $NAME &>/dev/null && echo $NAME | passwd --stdin $NAME&>/dev/null && echo "$NAME add OK!" || echo "$NAME is Exists"
        elif [[ $1 == del  ]];then
                userdel -rf $NAME &>/dev/null&& echo "$NAME delete OK!" || echo "$NAME no Such"
        else
                echo "ARG Error!"       
        fi
done

3、寫一個(gè)腳本:

計(jì)算100以內(nèi)所有能被3整除的正整數(shù)的和

#!/bin/bash
declare -i sum=0
for i in {1..100};do
        if (($i%3==0));then
                let sum=$[$sum+$i]
        fi
done
        echo $sum 

4、寫一個(gè)腳本:

計(jì)算100以內(nèi)所有奇數(shù)的和以及所有偶數(shù)的和

#!/bin/bash

for i in {1..100};do

if (($i%2==0));then

let sum=$sum+$i

fi

done

echo $sum

#!/bin/bash
for i in {1..100};do
if (($i%2==1));then
let sum=$sum+$i
fi
done
echo $sum

5、寫一個(gè)腳本,分別顯示當(dāng)前系統(tǒng)上所有默認(rèn)shell為bash的用戶和默認(rèn)shell為/sbin/nologin的用戶,并統(tǒng)計(jì)各類shell下的用戶總數(shù)。顯示結(jié)果如:

bash,3users,they are: root,redhat,gentoo

nologin,2users ,they are: bin ftp

#!/bin/bash

BASH_array=(`grep  "\<bash\>$" /etc/passwd | cut -d":" -f1`)

BASH_num=`grep -c "\<bash\>$" /etc/passwd`

NOLOGIN_array=(`grep  "\<nologin\>$" /etc/passwd | cut -d":" -f1`)

NOlOGIN_num=`grep -c "\<nologin\>$" /etc/passwd`

echo "bash,${BASH_num} users, they are:${BASH_array[@]}"

echo "nologin,${NOlOGIN_num} users, they are:${NOLOGIN_array[@]}"

while循環(huán):

適用于循環(huán)次數(shù)未知的場景,要有條件退出

while CONDITION;do

循環(huán)體

循環(huán)控制變量修正表達(dá)式

done

進(jìn)入條件:CONDITION測試為“真”

退出條件:CONDITION測試為“假”

while的特殊用法一:

while : ;do

done

while的特殊用法二:

while read LINE;do

done < /PATH/TO/SOMEFILE

練習(xí):計(jì)算100以內(nèi)所有正整數(shù)的和。

#!/bin/bash

declare -i i=1

declare -i num=0

while [ $i -le 100  ];do

let sum=$sum+$i

let i++

done

echo $sum

寫一個(gè)腳本

1.顯示一個(gè)菜單給用戶:

d|D) show disk usages.

m|M) show memory usages

s|S) show swap usages

*) quit

2.當(dāng)用戶給定選項(xiàng)后顯示相應(yīng)的內(nèi)容

擴(kuò)展:當(dāng)用戶選擇完成,顯示相應(yīng)的信息后,不退出;而讓用戶再一次選擇,再次顯示相應(yīng)內(nèi)容;除了用戶使用quit

#!/bin/bash

cat << EOF

d|D) show disk usages.

m|M) show memory usages.

s|S) show swap usages.

*) quit.

EOF

read -p"Please Choice:" CHOICE

while [ $CHOICE != 'quit' ];do

        case $CHOICE in

        d|D)

                echo -e "\033[32mdisk usage: \033[0m"

                df -Ph;;

        m|M)

                echo -e "\033[33mMemory usage: \033[0m"

                free -m |grep "Mem";;

        s|S)

                echo -e "\033[34mSwap usage: \033[0m"

                free -m |grep "Swap";;

        *)

                echo -e "\033[31mUnknown! \033[0m"

        esac

        read -p"Please Choice:" CHOICE

done

until循環(huán):
until CONDITION;do

循環(huán)體
循環(huán)控制變量修正表達(dá)式

done

進(jìn)入條件:CONDITION測試為“假”
退出條件:CONDITION測試為“真”

exit:退出循環(huán)

如果腳本沒有明確定義退出狀態(tài)碼,那么最后執(zhí)行的一條命令的退出碼即為腳本的退出狀態(tài)碼

break:提前退出循環(huán)

continue:提前結(jié)束本輪循環(huán),而進(jìn)入下一輪循環(huán)

示例:求100以內(nèi)正整數(shù)的和

練習(xí):分別使用for,while,until實(shí)現(xiàn)

1、分別求100以內(nèi)所有偶數(shù)之和,100以內(nèi)所有奇數(shù)之和;

#!/bin/bash

for m in {1..100}

do

        if(($m%2==0));then

         let num=$num+$m

        fi

done

        echo $num

#!/bin/bash

for m in {1..100}

do

        if(($m%2==1));then

         let num=$num+$m

        fi

done

        echo $num

2、創(chuàng)建10個(gè)用戶,user101-user110;密碼同用戶名

#!/bin/bash
for m in {101..110};do
i=user$m
! id $i &> /dev/null  && useradd $i && echo $i | passwd --stdin $i &> /dev/null || echo "$i is exists"
done

3、打印99乘法表;

#!/bin/bash
for m in {1..9}
do
        for((n=1;n<=m;n++))
        do
                echo -n "$n*$m = $(($m*$n))   " 
        done
        echo -e "\n"
done

4、打印逆序的九九乘法表

#!/bin/bash
for m in {9..1}
do
        for((n=1;n<=m;n++))
        do
                echo -n "$n*$m = $(($m*$n))   " 
        done
        echo -e "\n"
done

5、寫一個(gè)腳本,利用RANDOM生成10個(gè)隨機(jī)數(shù),并找出其中最大值,和最小值。

#!/bin/bash

#

declare -i max=0

declare -i min=0

for i in {1..10};do

        rand=$RANDOM

        [ $i -eq 1 ] && min=$rand

        if [ $i -le 9 ];then

                echo -n "$rand,"

        else

                echo $rand

        fi

        [ $rand -gt $max  ] && max=$rand

        [ $rand -lt $min ] && min=$rand

done

        echo "MAX:$max"
        echo "MIN:$min"

寫一個(gè)腳本:

1、通過ping命令測試192.168.0.151到192.168.0.254之間的所有主機(jī)是否在線,如果在線,就顯示“ip is up”,其中的IP要換為真正的IP地址,且以綠色顯示;如果不在線,就顯示“ip is  down ”,其中的IP地址換為真正的IP地址,且以紅色顯示。

要求:分別飾演while,until ,for(兩種形式)循環(huán)實(shí)現(xiàn)。

#!/bin/bash

declare -i LAST=150

while [ $LAST -le 254starry ];do

#until [ $LAST -gt 254 ];do

IP=222.73.22.$LAST

if ping -c 1 -W 1 $IP &> /dev/null;then

echo -e "IP:\033[32m $IP \033[0m is up" 

else 

echo -e "IP:\033[31m $IP \033[0m is down" 

fi

let LAST++

done

#!/bin/bash
for i in {150..254};do
#for ((i=150;i<=254;i++));do
IP=222.73.22.$i
if ping -c 1 -W 1 $IP &> /dev/null;then
echo -e "IP:\033[32m $IP \033[0m is up" 
else 
echo -e "IP:\033[31m $IP \033[0m is down" 
fi
done

寫一個(gè)腳本(前提:請為虛擬機(jī)新增一塊硬盤,架設(shè)它為/dev/sdb),為指定的硬盤創(chuàng)建分區(qū),

1)列出當(dāng)前系統(tǒng)上所有的磁盤,讓用戶選擇,如果選擇quit則退出腳本;如果用戶選擇錯(cuò)誤,就讓用戶重新選擇

2)當(dāng)用戶選擇后,提醒用戶確認(rèn)接下來的操作可能會(huì)損壞數(shù)據(jù),并請用戶確認(rèn),如果用戶選擇y就繼續(xù),n就退出,否則,讓用戶重新選擇

3)抹除那塊硬盤上的所有分區(qū)(提示:抹除所有分區(qū)后執(zhí)行sync命令,并讓腳本睡眠3秒種后再分區(qū));并為其創(chuàng)建三個(gè)主分區(qū),第一個(gè)為20M,第二個(gè)為512M,第三個(gè)為128M,且第三個(gè)為swap分區(qū)類型:(提示:將分區(qū)命令通過echo傳送給fdisk即可實(shí)現(xiàn))

#!/bin/bash

echo "Initial a Disk..."

echo -e "\033[31mWarning:Data will be lost!!!\033[0m"

fdisk -l | grep "Disk /dev/[vhs]d[a-z]" | awk -F: '{split($1,D," ");printf"Disk%d:%s\n",NR,D[2]}'

echo -en "\033[31mYour Choice:\033[0m"

read dk

if [ $dk == 'quit' ];then

        echo "Exiting..."

        exit 5

fi

until fdisk -l | grep "Disk /dev/[vhs]d[a-z]" | awk -F: '{print $1}' | grep "Disk $dk$" &>/dev/null ;do

echo -en "\033[31mChoose wrong, please choose again:\033[0m"

read dk

if [ $dk == 'quit' ];then

        echo "Exiting..."

        exit 5

fi

done

echo -en "\033[31mClear all data,Please Choice y or n:\033[0m"

read choice

until [ $choice == 'y' -o $choice == 'n'  ];do

echo -en "\033[31mChoose wrong, please choose y or n:\033[0m"

read choice

done

if [ $choice == 'n' ];then

echo "Quiting..."

exit 6

else

for i in `df -lh | grep "/dev/sdc" | awk '{print $1}'`;do

fuser -km $i

umount $i &>/dev/null

echo -e "\033[31m$i umount finish!\033[0m"

done

dd if=/dev/zero of=$dk bs=512 count=1 &>/dev/null

sync 

sleep 3

echo "

n

p

1

+20M

n

p

2

+512M

n

p

3

+128M

t

3

82

w" | fdisk $dk &>/dev/null

partprobe $dk  &>/dev/null

sync

sleep 2 

mke2fs -j ${dk}1 &>/dev/null

echo -e "\033[32m${dk}1 formatting finish!\033[0m"

mke2fs -j ${dk}2 &>/dev/null

echo -e "\033[32m${dk}2 formatting finish!\033[0m"

mkswap  ${dk}3 &>/dev/null

echo -e "\033[32m${dk}3 formatting finish!\033[0m"

fi

fdisk -l $dk

swapon ${dk}3

寫一個(gè)腳本,完成以下功能:(說明:此腳本能于同一個(gè)repo文件中創(chuàng)建多個(gè)yum源的指向)

①接受一個(gè)文件名做為參數(shù),此文件存放至/etc/yum.repos.d目錄中,且文件名以.repo為后綴

②在腳本中,提醒用戶輸入repo id ;如果為quit,則退出腳本;否則,繼續(xù)完成下面的步驟:

③repo name以及baseurl的路徑,而后以repo文件的格式將其保存至指定的文件中;

④enabled默認(rèn)為1,而gpgcheck默認(rèn)設(shè)定為0

⑤此腳本會(huì)循環(huán)執(zhí)行多次,除非用戶為repo id指定為quit

#!/bin/bash

REPO=/etc/yum.repos.d/$1

if [ -e $REPO ];then

echo "The  $1 Exist!"

exit 3

fi

echo -en "\033[32mPlease Enter Repo Id:\033[0m"

read REPOID

until [ $REPOID == "quit" ];do

echo  "[$REPOID]" >> $REPO

echo -en "\033[34mPlease Enter Repo Name:\033[0m"

read REPONAME

echo "name=$REPONAME" >> $REPO

echo -en "\033[34mPlease Enter baseurl:\033[0m"

read BASEURL

echo "baseurl=$BASEURL" >> $REPO

echo -e "enabled=1\ngpgcheck=0" >>$REPO

echo -en "\033[32mPlease Enter Repo Id:\033[0m"

read REPOID

done

echo "quit..."

exit 0

寫一個(gè)腳本,完成如下功能:(說明:此腳本能夠?yàn)橹付ňW(wǎng)卡創(chuàng)建別名,則指定地址;使用格式如;mkethalias.sh -v|--verbose -i ethx)

①-i 選項(xiàng)用于指定網(wǎng)卡;指定完成以后,要判斷其是否存在,如果不存在,就退出

②如果用戶知道的網(wǎng)卡存在,則讓用戶為其指定一個(gè)別名,此別名可以為空,如果不空,請確保其事先不存在,否則,要報(bào)錯(cuò),并讓用戶重新輸入

③在用戶輸入了一個(gè)正確的別名后,請用戶輸入地址和掩碼;并將其配置在知道的別名上;

④如果用戶使用了-v選選,則在配置完成后,顯示其配置結(jié)果信息:否則,將顯示

寫一個(gè)腳本:

①判斷一個(gè)值得的bash腳本是否有語法錯(cuò)誤:如果有錯(cuò)誤,則提醒用戶鍵入Q或者q無視錯(cuò)誤并退出,其他任何鍵可以通過vim打開這個(gè)值得的腳本

②如果用戶通過vim打開編輯后保存并退出時(shí)任然有錯(cuò)誤,則重復(fù)第一步中的內(nèi)容:否則,就正常關(guān)閉退出

#!/bin/bash
until `bash -n $1 &>/dev/null`;do
echo -ne "\033[31mSyntax error ,[Q|q]  to quit bash; others for vim $1: \033[0m"
read INPUT
if [ $INPUT != "q" -a  $INPUT != "Q" ];then
vim $1
continue
else
echo "quit...!"
exit 5
fi
done
echo "$1 bash is OK!"

#!/bin/bash

until `bash -n $1 &>/dev/null`;do

echo -ne "\033[31mSyntax error ,[Q|q]  to quit bash; others for vim $1: \033[0m"

read CHOSE

case $CHOSE in

Q|q)

echo "Syntax error ,quit!"

exit 3;;

*)

vim $1;;

esac

done

echo "$1 bash is OK!"

函數(shù)

function:功能

結(jié)構(gòu)化編程,不能獨(dú)立運(yùn)行,需要調(diào)用時(shí)執(zhí)行,可以被多次調(diào)用

定義一個(gè)函數(shù):

function FUNCNAME{

command

}

FUNCNAME(){

command

}

自定義執(zhí)行狀態(tài)返回值:

return #

0-255

寫一個(gè)腳本,判定192.168.0.200-192.168.0.254之間的主機(jī)哪些在線。要求:

①使用函數(shù)來實(shí)現(xiàn)一臺(tái)主機(jī)的判斷過程

②在主程序中來調(diào)用此函數(shù)判定指定范圍內(nèi)的所有主機(jī)的在線情況

#!/bin/bash
PING(){
if ping -c 1 -W 1 $1 &>/dev/null;then

return 0

else

return 1

fi
}
for i in {200.254};do
IP=192.168.0.$i
PING $IP
if [ $? -eq 0 ];then

echo -e "IP:\033[32m $IP \033[0m is up" 

else
         echo -e "IP:\033[31m $IP \033[0m is down" 

        fi

done

寫一個(gè)腳本:使用函數(shù)完成

①函數(shù)能夠接受一個(gè)參數(shù),參數(shù)為用戶名;判斷一個(gè)用戶存在,如果存在就返回此用戶的shell和UID;并返回正常狀態(tài)值;如果不存在就說此用戶不存在,并返回錯(cuò)誤狀態(tài)值

②在主程序中調(diào)用函數(shù)

擴(kuò)展①:在主程序中,讓用戶自己輸入用戶名后,傳遞函數(shù)來進(jìn)行判斷;

擴(kuò)展②:在主程序中,輸入用戶名判斷后不退出腳本,而是提示用戶繼續(xù)輸入下一個(gè)用戶名;如果用戶輸入的用戶不存在,請用戶重新輸入,但如果用戶輸入的是q或Q就退出。

#!/bin/bash
USERID(){
if id $1&>/dev/null;then

return 0

else

 return 1

fi
}
echo -ne "\033[32mPlease input UserName:\033[0m"
read USERNAME
while :;do

USERID $USERNAME

RETU=$?

if [ $USERNAME == "Q" -o $USERNAME == "q" ];then

echo -e "\033[35mquit...\033[0m"

exit 6

elif [ $RETU -eq 1 ];then

echo -ne "\033[31mUsers not exits!Please agin input:\033[0m"

read USERNAME

continue

else

cat /etc/passwd | grep "$USERNAME" | awk -F: '{printf "%s Uid:%d shell:%s\n",$1,$3,$NF}'

fi

echo -ne "\033[32mPlease input UserName:\033[0m"

read USERNAME

done

${parameter#*/word}
${parameter##*/word}

FILE=/usr/local/src

${FILE#*/}: usr/local/src

${FILE##*/}: src

${parameter%/*word}
${parameter%%/*word}

${FILE%/*}: /usr/local

${FILE%%/*}: 

服務(wù)樣例腳本:

#!/bin/bash

#

# chkconfig:2345 45 55

# description:This is my services!

FILE=/var/lock/subsys/mylinux

NAME=`basename $0`

STATUS(){

if [  -e $FILE ];then

  echo -e "\033[32m$NAME is running... \033[0m"

else

  echo -e "\033[31m$NAME is stoped\033[0m"

fi 

}

USAGE(){

  echo "/etc/init.d/$NAME {start|stop|restart|status}"

}

case $1 in

start)

  echo "starting..."

  touch $FILE;;

stop)

  echo "stoping..."

  rm -f $FILE &>/dev/null;;

restart)

  echo "restarting...";;

status)

  STATUS ;;

*)

  USAGE;;
esac

復(fù)制命令以及命令依賴的庫文件到新的根目錄

#!/bin/bash

MYROOT=/www/myroot

cplib(){

  libdir=${1%/*}

  newlib=$MYROOT$libdir

  [ ! -d $newlib ] && mkdir -p $newlib

  [ ! -e $MYROOT$1 ] && cp $1 $newlib && echo -e "\033[35m$1 copy finished!\033[0m"

}

cpcmd(){

  cmddir=${1%/*}

  newcmd=$MYROOT$cmddir

  [ ! -d $newcmd  ]  && mkdir -p $newcmd

  [ ! -e $MYROOT$1 ] && cp $1 $newcmd

  for i in  `ldd $1 | grep -o "/.*lib\(64\)\?/[^[:space:]]\+"`;do

    cplib $i

  done

}

echo -ne "\033[34mPlease input Command:\033[0m"

read CMD

until [ $CMD == 'q' ];do

  ! which $CMD &>/dev/null && echo -ne "\033[31mCommand not exist,Please againe input:\033[0m" && read CMD && continue

  COMMAND=`which $CMD | grep -v "alias" | grep  -o "[^[:space:]]\+"`

  cpcmd $COMMAND

  echo -e "\033[32m$COMMAND copy finished!\033[0m"

  echo -ne "\033[33mPlease input Command:\033[0m"

  read CMD
done

變量中的字符長度:${#var}

系統(tǒng)函數(shù)庫樣本:

SCREEN=`stty -F /dev/console size 2>/dev/null`

COLUMNS=${SCREEN#* }

[ -z $COLUMNS ]&& COLUMNS=80

SPA_COL=$[$COLUMNS-14]

RED='\033[1;31m'

GREEN='\033[1;32m'

BLUE='\033[1;34m'

NORMAL='\033[0m'

success(){

  string=$1

  RT_SPA=$[$SPA_COL-${#string}]

  echo -n $string

  for i in `seq 1 $RT_SPA`;do

    echo -n " "

  done

    echo -e "[   ${GREEN}OK${NORMAL}   ]"

}

failde(){

  string=$1

  RT_SPA=$[$SPA_COL-${#string}]

  echo -n $string

  for i in `seq 1 $RT_SPA`;do

    echo -n " "

  done

    echo -e "[ ${RED}FAILED${NORMAL} ]"

}

變量賦值:

${parameter:-word}:如果parameter為空或未定義,則變量展開為“word”;否則,展開為parameter的值

${parameter:+word}:如果parameter為空或未定義,不做任何操作”;否則,展開為“word”的值

${parameter:=word}:如果parameter為空或未定義,則變量展開為“word”;并將展開后的值賦值給parameter

${parameter:offset}

${parameter:offset:length}:取子串,從offset處的后一個(gè)字符開始,取lenth長的子串

腳本配置文件:

/etc/rc.d/init.d服務(wù)腳本

服務(wù)腳本支持配置文件:/etc/sysconfig/服務(wù)腳本同名的配置文件

局部變量:

local VAR_NAME=

a=1

test (){

local a=$[3+4]

}

test

for i in 'seq $i 10';do

    echo $i

done

mktemp命令:

mktemp - create a temporary file or directory
mktemp [OPTION]... [TEMPLATE]

常用選項(xiàng):

-d :創(chuàng)建臨時(shí)目錄

注意:mktemp會(huì)將創(chuàng)建的臨時(shí)文件名直接返回,因此,可以直接通過命令引用保存起來

信號:

kill -SIGNAL PID

1:HUP

2:INT(Ctrl+c)

9:KILL

15:TERM

腳本中,能實(shí)現(xiàn)信號捕捉,但9和1無法捕捉

trap命令:信號捕捉

trap 'COMMAND' 信號類別

trap 'echo "no quit"' INT  Ctrl+c的時(shí)候輸出 no quit

一個(gè)執(zhí)行多個(gè)語句,語句間用分號分隔

#!/bin/bash
TRAP(){
  rm -rf /var/tmp/test
  echo "quit and cleaning"
}
trap 'TRAP;exit 5' INT
mkdir -p /var/tmp/test
while true;do
   file=/var/tmp/test/file-`date +%H%M%S`   
   touch $file
   echo "Touch $file ok!"
   sleep 2
done

數(shù)組

如何聲明一個(gè)數(shù)組:

declare -a AA

賦值方法1:

AA[0]=jerry

AA[1]=tom

AA[2]=wendy

AA[6]=natasha

賦值方法2:

AA=(jerry  tom wendy natasha)

AA=([0]=jerry [1]=tom [2]=wendy [6]=natasha)

AA[3] =selina

AA[4] =nikita

${#AA[0]}:第一個(gè)元素的長度${#AA[1]}第二個(gè)元素個(gè)數(shù)的長度

${#AA[*]}: 元素個(gè)數(shù)

${#AA[@]}:元素個(gè)數(shù)

${AA[*]}: 所有元素
${AA[@]}:所有元素

練習(xí):

1、數(shù)組的元素個(gè)數(shù)為1-39

2、數(shù)組元素不能相同

3、顯示此數(shù)組各元素的值

#!/bin/bash

read -p "input numbers[1-39]:" NUM

declare -a ARRAY

BJ(){

   for j in `seq 0 $[${#ARRAY[@]}-1]`;do

      if [ $1 -eq ${ARRAY[$j]} ];then

        return 1

      fi

   done

   return 0

}

for i in `seq 0 $[$NUM-1]`;do

    while true;do

      RAND=$[$RANDOM%40]

      BJ $RAND

      if [ $? -eq 0 ];then

        break 

      fi

    done

      ARRAY[$i]=$RAND

      echo "${ARRAY[$i]}"

done

getopts命令:獲取選項(xiàng)

$OPTARG 獲取選項(xiàng)參數(shù)

$OPTIND 選項(xiàng)和參數(shù)的數(shù)量

bash腳本使用選項(xiàng)

#!/bin/bash

while getopts ":d:" SWITCH;do

   case $SWITCH in

     d)

        DESC=$OPTARG;;

    \?)

        echo "Usage:`basename $0` [-d descriprion] FILENAME";;

   esac

done

shift $[$OPTIND-1]

if ! grep "[^[:space:]]" $1 &> /dev/null;then

cat > $1 << EOF

#!/bin/bash

# Name:`basename $1`

# Description:$DESC

# Author:Tcj

# Version:0.0.1

# Datetime: `date "+%F %T"`

# Usage:`basename $1`

#

EOF

fi

vim + $1

until bash -n $1 &> /dev/null;do

    echo -ne "\033[31mSyntax error ,[Q|q]  to quit `basename $0`; others for vim $1: \033[0m"

    read CHOSE

    case $CHOSE in

 Q|q)

    echo "Syntax error ,quit!"

    exit 3;;

 *)

    vim $1;;

    esac

done

    echo "$1 bash grammar is OK!"

    chmod +x $1

練習(xí):寫一個(gè)腳本getinterface.sh,腳本可以接受選項(xiàng)(i,I,a),完成以下任務(wù)

1、使用以下形式:getinterface.sh [-i interface|-I IP|-a]

2、當(dāng)用戶使用-i選項(xiàng)時(shí),顯示其指定網(wǎng)卡的IP地址

3、當(dāng)用戶使用-I選項(xiàng)時(shí),顯示其后面的IP地址所屬的網(wǎng)絡(luò)接口

4、當(dāng)用戶單獨(dú)使用-a選項(xiàng)時(shí),顯示所有網(wǎng)絡(luò)接口及其IP地址(除lo除外)

#!/bin/bash

# Name:getinterface.sh

# Description: Get ehternet information

# Author:Tcj

# Version:0.0.1

# Datetime: 2016-11-28 23:12:23

# Usage:getinterface.sh [-i INTERFACE|-I IP|-a ]

#

GETIP(){

  if ! ifconfig | grep -o "^[^[:space:]]\+" | grep $1  &>/dev/null;then

     echo "Wrong ehtercard!"

     exit 5

  fi

  IP=`ifconfig $1 | grep -o "inet addr:[0-9\.]\+" | cut -d":" -f2`

}

GETNET(){

  if ! ifconfig  | grep -o "inet addr:[0-9\.]\+" | cut -d":" -f2 | grep $1 &>/dev/null;then

     echo "Wrong IP!"

     exit 6

  fi

  NETWORK=`ifconfig | grep -B 1 "inet addr:$1" | grep -o "^[^[:space:]]\+"`

}

GETALL(){

  for i in `ifconfig | grep -o "^[^[:space:]]\+" | grep -v "lo"`;do

     GETIP $i

     echo "$i:$IP"

  done

}

USAGE(){

  echo "usage:`basename $0`[-i INTERFACE|-I IP|-a ]"

}

while getopts ":i:I:a" OPT;do

   case $OPT in

      i)

 GETIP $OPTARG

 echo -e "$OPTARG:\033[32;1m$IP\033[0m";;

      I)

         GETNET $OPTARG

 echo -e "$OPTARG:\033[32;1m$NETWORK\033[0m";;

      a)

         GETALL;;

      \?)

         USAGE;;

   esac

done

【騰訊云】云服務(wù)器、云數(shù)據(jù)庫、COS、CDN、短信等云產(chǎn)品特惠熱賣中

發(fā)表評論

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前評論:3   其中:訪客  0   博主  0

    • avatar 合歡 0

      挺好的,祝你快樂

      • avatar 三五 0

        偶然來訪,受益良多!

        • avatar 衣皇后 1

          掐指一算,這個(gè)博客能風(fēng)光一百年!