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遍歷
例:
顯示當前系統上所有默認shell爲bash的用戶的用戶名、UID以及此類所有用戶的UID之和
找出默認shell爲bash的用戶名,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=1;let B=2;let 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: f1和f2是否爲同一個文件的兩個硬鏈接;
組合條件測試:
組合測試條件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) 顯式使用echo或printf命令;
(b) 函數中某些命令運行結果產生的輸出;
函數退出狀態碼:
默認其退出碼取決於函數體最後執行的那個語句的退出狀態碼;
自定義退出狀態碼:
return[N]
0-255
0:成功
1-255: 失敗
注意:函數運行時,一旦遇到return語句即會退出整個函數的運行;
函數可接受參數:
調用函數時,可以傳遞參數給函數,傳遞方法類似向腳本傳遞參數的方法,例如
函數名 arg1 arg2 arg3...
在函數中可使用$1,$2, ...來調用這些參數;
可在函數中使用特殊變量:$#,$@, $*
練習:寫一個腳本
(1) 用函數實現返回一個用戶的UID和SHELL;用戶名通過參數傳遞而來
(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]
bash從4.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;