數組css
什麼是數組?linux
變量:存儲單個元素的內存空間;shell
數組:存儲多個元素的連續的內存空間;編程
數組名:整個數組只有一個名字;api
數組索引:編號從0開始;數組
數組名[索引], ${ARRAY_NAME[INDEX]}bash
注意:bash-4及以後的版本,支持自定義索引格式,而不單單是0,1,2,...數字格式;網絡
此類數組稱之爲「關聯數組」ide
聲明數組:工具
declare -a NAME:聲明索引數組;
declare -A NAME:聲明關聯數組;
數組中元素的賦值方式:
(1) 一次只賦值一個元素; ARRAY_NAME[INDEX]=value
(2) 一次賦值所有元素;ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
(3) 只賦值特定元素;ARRAY_NAME=([0]="VAL1" [3]="VAL4" ...)
注意:bash支持稀疏格式的數組;
(4) read -a ARRAY_NAME 引用數組中的元素:${ARRAY_NAME[INDEX]}
注意:引用時,只給數組名,表示引用下標爲0的元素;
數組的長度(數組中元素的個數):
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
示例:生成10個隨機數,並找出其中的最大值和最小值;
#!/bin/bash # declare -a rand declare -i max=0 for i in {0..9}; do rand[$i]=$RANDOM echo ${rand[$i]} [ ${rand[$i]} -gt $max ] && max=${rand[$i]} done
echo "MAX: $max"
練習:定義一個數組,數組中的元素是/var/log目錄下全部以.log結尾的文件;統計其下標爲偶數的文件中的行數之和;
#!/bin/bash # declare -a files files=(/var/log/*.log) declare -i lines=0 for i in $(seq 0 $[${#files[*]}-1]); do if [ $[$i%2] -eq 0 ]; then let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1) fi done echo "Lines: $lines."
引用數組中的全部元素:
${ARRAY_NAME[*]}
${ARRAY_NAME[@]}
數組元素切片: ${ARRAY_NAME[@]:offset:number}
offset:要路過的元素個數;
number:要取出的元素個數;省略number時,表示取偏移量以後的全部元素;
向非稀疏格式數組中追加元素:ARRAY_NAME[${#ARRAY_NAME[*]}]=
刪除數組中的某元素:unset ARRAY[INDEX]
關聯數組:
declare -A ARRAY_NAME 注:聲明一個數組變量
ARRAY_NAME=([index_name1]="value1" [index_name2]="value2" ...)
字串切片
bash的內置字符串處理工具:
字符串切片:${var:offset:number}
取字符串的子串;取字符趾的最右側的幾個字符:${var: -length}
注意:冒號後必須有一個空白字符;
基於模式取子串:
一、${var#*word}:其中word是指定的分隔符;功能:自左而右,查找var變量所存儲的字符串中,第一次出現的word分隔符,刪除字符串開頭至此分隔符之間的全部字符;
二、${var##*word}:其中word是指定的分隔符;功能:自左而右,查找var變量所存儲的字符串中,最後一次出現的word分隔符,刪除字符串開頭至此分隔符之間的全部字符;
舉例:mypath="/etc/init.d/functions"
三、${mypath##*/}: functions
四、${mypath#*/}: etc/init.d/functions
五、${var%word*}:其中word是指定的分隔符;功能:自右而左,查找var變量所存儲的字符串中,第一次出現的word分隔符,刪除此分隔符至字符串尾部之間的全部字符;
六、${var%%word*}:其中word是指定的分隔符;功能:自右而左,查找var變量所存儲的字符串中,最後一次出現的word分隔符,刪除此分隔符至字符串尾部之間的全部字符;
舉例:mypath="/etc/init.d/functions"
七、${mypath%/*}: /etc/init.d
舉例:url=http://www.magedu.com:80
八、${url##*:}
九、${url%%:*}
查找替換:
一、${var/PATTERN/SUBSTI}:查找var所表示的字符串中,第一次被PATTERN所匹配到的字符串,將其替換爲SUBSTI所表示的字符串;
二、${var//PATTERN/SUBSTI}:查找var所表示的字符串中,全部被PATTERN所匹配到的字符串,並將其所有替換爲SUBSTI所表示的字符串;
四、${var/#PATTERN/SUBSTI}:查找var所表示的字符串中,行首被PATTERN所匹配到的字符串,將其替換爲SUBSTI所表示的字符串;
五、${var/%PATTERN/SUBSTI}:查找var所表示的字符串中,行尾被PATTERN所匹配到的字符串,將其替換爲SUBSTI所表示的字符串;
注意:PATTERN中使用glob風格和通配符;
查找刪除:
一、${var/PATTERN}:以PATTERN爲模式查找var字符串中第一次的匹配,並刪除之;
二、${var//PATERN}
三、${var/#PATTERN}
四、${var/%PATTERN}
字符大小寫轉換:
一、${var^^}:把var中的全部小寫字符轉換爲大寫;
二、${var,,}:把var中的全部大寫字符轉換爲小寫;
三、變量賦值:
四、${var:-VALUE}:若是var變量爲空,或未設置,那麼返回VALUE;不然,則返回var變量的值;
五、${var:=VALUE}:若是var變量爲空,或未設置,那麼返回VALUE,並將VALUE賦值給var變量;不然, 則返回var變量的值;
六、${var:+VALUE}:若是var變量不空,則返回VALUE;
七、${var:?ERROR_INFO}:若是var爲空,或未設置,那麼返回ERROR_INFO爲錯誤提示;不然,返回var值;
寫一個腳本:
ping命令去查看172.16.1.1-172.16.67.1範圍內的全部主機是否在線;在線的顯示爲up, 不在線的顯示down,分別統計在線主機,及不在線主機數;
分別使用for, while和until循環實現。
for循環實現方式
#!/bin/bash # declare -i uphosts=0 declare -i downhosts=0 for i in {1..17}; do if ping -W 1 -c 1 172.16.$i.1 &> /dev/null; then echo "172.16.$i.1 is up." let uphosts+=1 else echo "172.16.$i.1 is down." let downhosts+=1 fi done echo "Up hosts: $uphosts, Down hosts: $downhosts."
while循環實現方式:
#!/bin/bash # declare -i uphosts=0 declare -i downhosts=0 declare -i i=1 hostping() { if ping -W 1 -c 1 $1 &> /dev/null; then echo "$1 is up." return 0 else echo "$1 is down." return 1 fi } while [ $i -le 67 ]; do hostping 172.16.$i.1 [ $? -eq 0 ] && let uphosts++ || let downhosts++ let i++ done echo "Up hosts: $uphosts, Down hosts: $downhosts."
寫一個腳本,實現:
能探測C類、B類或A類網絡中的全部主機是否在線;
#!/bin/bash # cping() { local i=1 while [ $i -le 5 ]; do if ping -W 1 -c 1 $1.$i &> /dev/null; then echo "$1.$i is up" else echo "$1.$i is down." fi let i++ done } bping() { local j=0 while [ $j -le 5 ]; do cping $1.$j let j++ done } aping() { local x=0 while [ $x -le 255 ]; do bping $1.$x let x++ done }
信號捕捉trap
trap 'COMMAND' SIGNALS 注:捕捉到 SIGNALS ,就執行'COMMAND'
常能夠進行捕捉的信號:HUP, INT(ctrl +c )
提示用戶輸入一個IP地址或網絡地址;獲取其網絡,並掃描其網段;
信號捕捉示例: #!/bin/bash # declare -a hosttmpfiles trap 'mytrap' INT mytrap() { echo "Quit" rm -f ${hosttmpfiles[@]} exit 1 } for i in {1..50}; do tmpfile=$(mktemp /tmp/ping.XXXXXX) if ping -W 1 -c 1 172.16.$i.1 &> /dev/null; then echo "172.16.$i.1 is up" | tee $tmpfile else echo "172.16.$i.1 is down" | tee $tmpfile fi hosttmpfiles[${#hosttmpfiles[*]}]=$tmpfile done rm -f ${hosttmpfiles[@]}
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
編外補充:
練習:寫一個腳本,完成以下功能
(1) 提示用戶輸入一個可執行命令的名稱;
(2) 獲取此命令所依賴到的全部庫文件列表;
(3) 複製命令至某目標目錄(例如/mnt/sysroot,即把此目錄看成根)下的對應的路徑中
bash, /bin/bash ==> /mnt/sysroot/bin/bash
useradd, /usr/sbin/useradd ==> /mnt/sysroot/usr/sbin/useradd
(4) 複製此命令依賴到的全部庫文件至目標目錄下的對應路徑下;
/lib64/ld-linux-x8664.so.2 ==> /mnt/sysroot/lib64/ld-linux-x8664.so.2
進一步:
每次複製完成一個命令後,不要退出,而是提示用戶繼續輸入要複製的其它命令,並重復完成如上所描述的功能;直到用戶輸入「quit」退出腳本;
在bash中使用ACSII顏色
\033[31m hello \033[0m
##m:
左側#:
3:前景色
4:背景色
右側#:顏色種類
1, 2, 3, 4, 5, 6, 7
#m:
加粗、閃爍等功能;
多種控制符,可組合使用,彼此間用分號隔開;
dialog命令可實現窗口化編程;
各窗體控件使用方式;
如何獲取用戶選擇或鍵入的內容?
默認,其輸出信息被定向到了錯誤輸出流;
《高級bash編程指南》,《Linux命令行和shell腳本編程寶典》