bash腳本知識

bash [OPTION] FILENAME

例:bash -x ./test.sh

-n :檢查腳本語法錯誤

注意:不是命令語法錯誤

-x: 調試運行

 

for循環

 

語法1

for 變量名 in 循環列表; do

循環體

done

 

List的生成方式:

1、整數序列:{start..end},例如:{1..10}

2、整數序列:seq 開始數步長結束數,例如:$(seq 1 2 10)

3、命令的執行結果:例如,$(ls/var) `ls /var`

語法2

for ((變量初始值賦值;循環條件;變量的修正表達式)); do

循環體

done

 

例:1+2+3+…+10                                                                            

(1)      sum=0

for i in {1,10};do

let sum+=$i

done

echo $sum

(2)      sum=0

for i in `seq 1 10`;do

let sum+=$i

done

echo $sum

(3)      sum=0

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

let sum+=$i

done

echo $sum

例:   2+4+6+…+10

(1)       for i in `seq 2 210`;do

let sum+=$i

done

echo $sum

(2)      for ((i=2;i<=10;i=$i+2));do

letsum+=$i

done

echo$sum

 

for遍歷

例:

顯示當前系統上所有默認shellbash的用戶的用戶名、UID以及此類所有用戶的UID之和

找出默認shellbash的用戶名,uid

#!/bin/bash

grep '/bin/bash$' /etc/passwd|cut -d':' -f1,3

uid=`grep '/bin/bash$' /etc/passwd|cut -d':' -f3`

#計算uid之和

for i in $uid;do

        letsum_id+=$i

done

echo $sum_id

 

練習:寫一個腳本

(1) 接受一個以上文件路徑作爲參數;

(2) 顯示每個文件擁有的行數;

(3) 總結說明本次共爲幾個文件統計了其行數;

#!/bin/bash

#

echo"Files: $@."

forfile in $@; do

    lines=$(wc -l $file | cut -d' ' -f1)

    echo "$file has $lines line(s)."

done

echo"Total files: $#."

 

練習:寫一個腳本

(1) 傳遞兩個以上字符串當作用戶名;

(2) 創建這些用戶;且密碼同用戶名;

(3) 總結說明共創建了幾個用戶;

 

#/bin/bash

#

foruser in $@; do

useradd$user

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

done

echo"Total users: $#."

 

算術運算:

如何定義整型變量?

(1)let Var_Name=INTEGER_VALUE

letnum1=3

 

(2)declare -i Var_Name=INTEGER_VALUE

declare-i num2=6

 

注意:即使沒有定義變量類型爲整型,字符型的整數依然可以參與算術運算,是因爲bash會進行隱式的數據類型轉換

 

bash的算術運算:

(1)let: let Var_Name=ARITHMATIC_EXPRESSION

例:let A=1let B=2let C=$A+$B  ==>C=3

         A=1 ; B=2 ; C=$A+$B==>C=1+2

(2)$[]: Var_Name=$[ARITHMATIC_EXPRESSION]

例:C=$[$A+$B]

(3) $(())Var_Name=$((ARITHMATIC_EXPRESSION))

例: C=$(($A+$B))

(4) expr命令:Var_Name=$(exprEXPRESSION)

  Var_Name=$(expr ARGU1 operator $ARGU2)

例:C=`expr$A+$B`

 

算術運算:+-*/%:取模,取餘數;**:冪運算

 

條件測試:

bash命令執行結束後有退出狀態碼:

0-255

0:成功執行

1-255:執行失敗

 

可以用 exit 數字 [例:exit 0] 設置腳本退出時的狀態碼

 

 

整數測試:

雙目操作符:需要兩個操作數;

$A -gt $B: 大於

-ge:大於等於

-lt:小於

-le:小於等於

-ne:不等於

-eq:等於

字符串測試:$str1, $str2

雙目:

"$str1" >"$str2": 測試str1是否大於str2,是則爲真,不是則爲假;

<:是否小於;

==: 是否等於;

!=: 是否不等於;

 

單目:

-z "$str1": 測試str1字符串是否爲空,空則爲真,不空則爲假;

-n "$str1": 測試str1字符串是否不空,不空則爲真,空則爲假;

 

模式匹配測試:

"$str1"=~PATTERN:

如果str1字符串能夠被後面的模式所匹配則爲真,否則爲假;

練習:寫一個腳本,完成如下功能

(1) 傳遞一個磁盤設備文件路徑給腳本,判斷此設備是否存在;

(2) 如果存在,則顯示此設備上的所有分區信息;

#!/bin/bash

#

if! [[ "$1" =~ ^/dev/[sh]d[a-z]$ ]]; then

   echo "Not a device file."

   exit 1

fi

iffdisk -l /dev/[hs]d[a-z] | grep "^Disk" | grep "$1"&> /dev/null; then

    fdisk -l $1

else

    echo "No such disk."

fi

  文件測試:$file

存在性及類型測試:

-e $file: 文件是否存在,存在爲真,否則爲假;

-a $file: 同上;

-f $file: 文件是否存在且爲普通文件,是則爲真,不是則假;

-d $file:路徑是否存在且爲目錄文件;

-h|-L $file: 路徑是否爲符號鏈接文件;

-b $file: 路徑是否存在且爲塊設備文件;

-c $file: 路徑是否存在且爲字符設備文件;

-S $file: 路徑是否存在且爲套接字文件;

-p $file: 路徑是否存在且爲管道文件;

 

文件權限判斷:

-r $file: 文件是否存在且對當前用戶可讀;

-w $file: 文件是否存在且對當前用戶可寫;

-x $file: 文件是否存在且對當前用戶可執行;

 

-u $file: 文件是否存在且擁有SUID權限;

-g $file: 文件是否存在且擁有SGID權限;

-k $file:文件是否存在且且擁有sticky權限;

 

-O $file: 當前用戶是否路徑指向的文件的屬主;

-G $file:當前用戶是否屬於文件的屬組;

 

文件時間戳相關:

-N $file:文件自從最近一次的讀訪問之後,是否又被修改過;

 

$f1 -nt $f2: f1是否新於f2

$f1 -ot $f2: f1是否舊於f2

$f1 -ef $f2: f1f2是否爲同一個文件的兩個硬鏈接;

組合條件測試:

組合測試條件1:組合測試表達式

或:-o, [ COND_EXPR1 -o COND_EXPR2 ]

與:-a

非:!         

例:["$hname" == "localhost" -o "$hname" =="(none)" ]

 

組合測試條件2:組合測試語句

與:&&

或:||

非:!

例:["$hname" == "localhost" ] || [ "$hname" =="(none)" ]

 

if語句的語法:

(1)單分支:

if 判斷條件; then

分支

fi

(2)雙分支

if 判斷條件; then

分支1

else

分支2

fi

(3)多分支

if 判斷條件1;then

elif 判斷條件2;then

elif 判斷條件3;then

else

fi

注意:if語句只有在判斷兩個值比較時,才用[ ]

  若是if`id root &>/dev/null` ;then

  echo root

  fi

             不用加[ ]

if [ $A -lt $B ];then

echo $A

      elif [ $str1 == $str2];then

echo $str1

      fi

 

 

case語句的語法:

case變量引用in

PATTERN1)

分支1

;;

PATTERN2)

分支2

;;

...

*)    *表示都不匹配時                            

分支n

;;

esac

 

注意:

PATTERN可使用通配符:

*: 任意長度任意字符;

?: 任意單個字符;

[]:指定範圍內的任意單個字符;

a|b|c:或者

 

例:

練習:寫一個腳本

(1) 能接受四個參數:start,stop, restart, status

start: 輸出“starting腳本名 finished.”

...

(2) 其它任意參數,均報錯退出;

#!/bin/bash

#

svc=$(basename$0)

lockfile=/tmp/${svc}

case$1 in

start)

    if [ -e $lockfile ]; then

         echo "$svc is running"

         exit 0

    else

        echo "starting $svcfinished."

        touch $lockfile && exit 0

    fi

    ;;

stop)

    echo "stopping $svc finished."

    ;;

restart)

    echo "restarting $svc finished."

    ;;

status)

    echo "running or stopped."

    ;;

*)

    echo "Usage: $svc{start|stop|restart|status}"

    exit 1

    ;;

esac

 

交互式編程 read

read -p "註釋信息" 變量名

例: read -p "Input one Number :" num1

read -t # :指定超時時間

例: read -t 5 "Input one Number :" num1    [5s內用戶沒輸入,則繼續向下進行,而num1爲空]

-a 數組;-A 關聯數組

 

練習:寫一個腳本,提示用戶輸入一個用戶名;

在用戶存在時,判斷其UID是否同GID

同,則顯示“Good guy”不同,則顯示“Bad guy”

 

#!/bin/bash

#

read-p "Plz enter a user name: " name

 

!id $name &> /dev/null && echo "No this user."&& exit 1

 

if[ `id -u $name` == `id -g $name` ]; then

    echo "Good guy"

else

    echo "Bad guy"

fi

 

while循環語句的語法:

 

whileCONDITION; do

循環體

循環控制變量的修正表達式

done

 

其中,“CONDITION”,當條件測試結果爲“真”,則進入循環;爲“假”時,終止循環;循環控制變量要用於CONDITION中,以實現循環條件構建;

 

示例:求100以內所在正整數之和;

#!/bin/bash

#

declare-i i=1

while[ $i -le 100 ]; do

    let sum+=$i

    let i++

done

echo"$sum"        

 

示例:打印九九乘法法;

#!/bin/bash

#

declare-i i=1

while[ $i -le 9 ]; do

    let j=1

    while [ $j -le $i ]; do

        echo -n -e"${j}X${i}=$[$i*$j]\t"

        let j++

    done

    echo

    let i++

done

 

示例:寫一個腳本,判斷給定的用戶是否登錄了當前系統;

(1) 如果登錄了,則顯示用戶登錄,腳本終止;

(2) 3秒鐘,查看一次用戶是否登錄;

#!/bin/bash

#

read-p "Plz enter a user name: " name

while! who | grep "^$name\>" &> /dev/null; do

    sleep 3

done

echo"$name is here."        

 

示例:寫一個腳本,顯示用戶選定要查看的信息;

cpu)display cpu info

mem)display memory info

disk)display disk info

quit)quit

非此四項選擇,則提示錯誤,並要求用戶重新選擇,只到其給出正確的選擇爲止;

#!/bin/bash

#

cat<< EOF

                cpu) display cpu info

                mem) display memory info

                disk) display disk info

                quit) quit

EOF

read-p "your option: " option

while[ "$option" != 'cpu' -a "$option" != 'mem' -a"$option" != 'disk' -a "$option" != 'quit' ]; do

    echo "Wrong option."

    read -p "your option again: "option

done

case$option in

cpu)

     lscpu ;;

mem)

     free ;;

disk)

     fdisk -l /dev/[sh]d[a-z] ;;

quit)

     exit 0

esac        

 while循環的特殊用法:

 

(a)用於遍歷指定文件的每一行;

while read變量名; do

循環體

done < /PATH/TO/SOMEFILE

 

變量用於保存一行數據;直到遇到文件尾,數據終止,循環退出;

 

示例:找出其UID爲偶數的用戶,顯示用戶名和其UID

#!/bin/bash

#

[$UID -ne 0 ] && echo "Only root can excute this script."&& exit 1

while read line; do

   userid=$(echo $line | cut -d: -f3)

    if [$[$userid%2] -eq 0 ]; then

        echo$line | cut -d: -f1,3

    fi

done < /etc/passwd        

 

示例:將給定的偶數行內字符統統修改爲大寫之後輸出;

#!/bin/bash

#

declare-i linenumber=1

read-p "Plz enter a file path: " file

while read line; do

    if [$[$linenumber%2] -eq 0 ]; then

        echo -n"$linenumber "

        echo$line |tr 'a-z' 'A-Z'

    fi

    letlinenumber++

done < $file

 

(b) 死循環

while true; do

循環體

done

 

循環控制:

break [N]:結束循環;

退出當前循環;N表示循環嵌套層次;

continue [N]:提前結束本輪循環,而直接進入下一輪循環條件判斷

 

示例:求100以內所有偶數之和;

 

#!/bin/bash

#

declare-i evensum=0

declare-i i=0

while[ $i -le 100 ]; do

    let i++

    if [ $[$i%2] -eq 1 ]; then

        continue

    fi

    let evensum+=$i

done

echo"$evensum"

 

示例:判斷centos是否登錄,如果登錄則顯示之;否則,每3秒查看centos是否登錄;

 

#!/bin/bash

#

user='centos'

whiletrue; do

    if who | grep "^$user\>"&> /dev/null; then

        break

    fi

    sleep 3

done

echo"$user is here."

 

 

until循環語句的語法:

 

until CONDITION; do

循環體

控制變量修正語句

done

 

CONDTION條件爲“假”時,執行循環;爲“真”時退出循環;while相反

 

示例:100以內所有正整數之和:

#!/bin/bash

#

declare-i i=1

declare-i sum=0

until[ $i -gt 100 ]; do

    let sum+=$i

    let i++

done

echo"$sum"

 

函數function的語法:

語法結構:

(1) function 函數名 {

 函數體

       }

 

(2) 函數名() {

 函數體

      }

 

調用函數:函數名        例: checkUser centos [checkUser 爲函數名centos 爲傳入的參數]

 

函數的返回值:

函數執行過程結果向調用者的回饋;

(a) 顯式使用echoprintf命令;

(b) 函數中某些命令運行結果產生的輸出;

函數退出狀態碼:

默認其退出碼取決於函數體最後執行的那個語句的退出狀態碼;

自定義退出狀態碼:

return[N]

0-255

0:成功

1-255: 失敗

注意:函數運行時,一旦遇到return語句即會退出整個函數的運行;

 

函數可接受參數:

調用函數時,可以傳遞參數給函數,傳遞方法類似向腳本傳遞參數的方法,例如

函數名 arg1 arg2 arg3...

在函數中可使用$1,$2, ...來調用這些參數;

可在函數中使用特殊變量:$#,$@, $*

 

 

練習:寫一個腳本

(1) 用函數實現返回一個用戶的UIDSHELL;用戶名通過參數傳遞而來

(2) 提示用戶輸入一個用戶名或輸入“quit”退出;

當輸入的是用戶名,則調用函數顯示用戶信息;

當用戶輸入quit,則退出腳本;

進一步地:顯示鍵入的用戶相關信息後,再次提醒輸出用戶名或quit

#!/bin/bash

checkUser(){

userid=`id -u $1`

usershell=`grep"^$1" /etc/passwd |cut -d: -f7`

echo"$1 uid :$userid "

echo"$1 shell :$usershell"

}

whiletrue ;do

read-p "input username: " name

if! [ -z $name ];then

if`id $name&>/dev/null`;then

checkUser $name

elif[ $name == 'q' ];then

exit0

else

echo"Input or quit"

fi

else

echo"Input or quit"

fi

  done

 

 

數組語法:

數組:變量陣列,通過同一個名字進行存取操作;

連續的多個獨立的內存空間(元素),每個內存空間相當於一個變量;

數組元素:數組名[索引]

索引:從0開始編號

 

聲明數組:

declare-a Array_Name

 

bash的數組支持稀疏格式;

 

數組元素賦值:

(1) 一次只賦值一個元素

a_name[index]=value

 

weekday[0]="Sunday"

weekday[1]="Monday"

 

(2) 一次賦值全部元素

weekday=("Sunday""Monday" "Tuesday")

 

(3) 指定索引進行賦值

weekdays=([0]="Sunday"[3]="Thu" [6]="Sat")

 

(4)read -a a_name

 

引用數組元素:${array_name[index]}

 

獲取數組長度:${#array[*]}, ${#array[@]}

即數組中元素的個數;

 

練習:寫一個腳本,生成10個隨機數,保存至數據組中;而後顯示數組索引爲偶數的元素的值;

 

#!/bin/bash

#

for((i=0;i<10;i++)); do

    rand[$i]=$RANDOM

    echo ${rand[$i]}

done

 

echo"========================"

 

fori in `seq 0 2 9`; do

    echo ${rand[$i]}

done

 

 

練習:寫一個腳本

定義一個數組,數組元素爲/var/log目錄下所有以.log結尾的文件的名字;顯示每個文件的行數;

 

#!/bin/bash

#

declare-a files

 

files=(/var/log/*.log)

 

fori in `seq 0 $[${#files[*]}-1]`; do

    wc -l ${files[$i]}

done

 

數組切片:從數組中挑選指定的某個或某些元素:

${array[@]:offset:number}

 

offset: 偏移的元素的個數;

number:要取出的元素的個數;

 

${array[@]:offset}

取出偏移量之後剩餘所有的元素;

 

${array[@]}

 

從數組中刪除元素:

unsetarray[index]

 

bash4.0版本起支持關聯數組:

數組索引可爲自定的字符串;

 

定義方法:declare -A array_name

 

練習:寫一個腳本,能從所有同學中隨機挑選一個同學回答問題;

進一步地:可接受一個參數,做爲要挑選的同學的個數;

 

 

bash的字符串處理:

 

字符串切片:${var:offset:length}

 

取出字符串的最後幾個字符:${var: -length}

注意:-length之前有空白字符;

 

基於模式取子串:

${var#*word}:自左而右,查找var變量中存儲的字符串中第一次出現的由word所指明的字符,刪除此字符及其左側的所有內容;

${var##*word}:自左而右,查找var變量中存儲的字符串中最後一次出現的由word所指明的字符,刪除此字符及其左側的所有內容;

${var%word*}:自右而左,查找var變量中存儲的字符串中第一次出現的由word所指明的字符,刪除此字符及其右側的所有內容;

${var%%word*}:自右而左,查找var變量中存儲的字符串中最後一次出現的由word所指明的字符,刪除此字符及其右側的所有內容;

 

示例:

url="http://www.magedu.com:80"

 

取端口:echo ${url##*:}

取協議:echo ${url%%:*}

 

查找替換:

${var/pattern/replacement}:查找var變量存儲的字符中第一次由pattern匹配到的內容,並替換爲replacement

${var//pattern/replacement}:查找var變量存儲的字符中所有能夠由pattern匹配到的內容,並替換爲replacement

${var/#pattern/replacement}:查找var變量存儲的字符中最開始處能夠由pattern匹配到的內容,並替換爲replacement

${var/%pattern/replacement}:查找var變量存儲的字符中最後位置能夠由pattern匹配到的內容,並替換爲replacement

 

查找刪除:

 

${var/pattern}:查找var變量存儲的字符中第一次由pattern匹配到的內容,並刪除;

${var//pattern}:查找var變量存儲的字符中所有能夠由pattern匹配到的內容,並刪除;

${var/#pattern}:查找var變量存儲的字符中最開始處能夠由pattern匹配到的內容,並刪除;

${var/%pattern}:查找var變量存儲的字符中最後位置能夠由pattern匹配到的內容,並刪除;

 

字符串大小寫轉換:

${var^^}:把var變量中的所有小寫字母,統統替換爲大寫;

${var,,}:把var變量中的所有大寫字母,統統替換爲小寫;

 

變量賦值:

${var:-word}:如果變量var爲空或未聲明,則返回word所表示的字符串;否則,則返回var變量的值;

${var:=word}:如果變量var爲空或未聲明,則返回word所表示的字符串,並且把word賦值爲var變量;否則,則返回var變量的值;

${var:?error}:如果變量var爲空或未聲明,則返回error爲錯誤信息;否則,則返回var變量的值;

${var:+word}:如果變量var爲空或未聲明,忽略;否則,則返回word

 


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