這篇文章為大家分享Linux中bash編程的使用方法。文章介紹了bash的變量、bash的配置文件以及bash語句的語法結構和函數的使用,希望大家通過這篇文章能有所收獲。
一、bash編程的變量
本地變量:只對當前shelll進程有效的變量,對其他shell進程無效,包含當前shell進程的子進程。
即向變量的存儲空間保存數據,如下
[root@localhost ~]# VAR_NAME=VALUE
格式為:${VAR_NAME}
" ":弱引用,里面的變量會被替換;
' ':強引用,里面的所有字符都是字面量,直接輸出,所見即所得;
對當前shell進程及其子shell有效,對其他的shell進程無效!
定義:VAR_NAME=VALUE
導出:export VAR_NAME
撤銷變量:unset VAR_NAME
只讀變量:readonly VAR_NAME
在shell腳本中定義,只可以在shell腳本中使用!
$1,$2...,${10}
shell對一些參數做特殊處理,這些參數只能被引用而不能被賦值!
$#:傳遞到腳本的參數個數
$*:顯示所有向腳本傳遞的參數 //與位置變量不同,此選項參數可超過9個
$$:獲取當前shell的進程號
$!:執行上一個指令的進程號
$?:獲取執行的上一個指令的返回值 //0為執行成功,非零為執行失敗
$-:顯示shell使用的當前選項,與set命令功能相同
$@ 與$*相同,但是使用時加引號,并在引號中返回每個參數
set:查看當前shell進程中的所有變量;
export、printenv、env:查看當前shell進程中的所有環境變量;
1)不能使用程序中的關鍵字;
2)只能使用數字、字母和下劃線,不可使用數字開頭;
3)系統變量默認都是大寫,自定義變量盡量不要與系統變量沖突;
4)盡量做到見名知意;
1)數值型:精確數值(整數)、近似數值(浮點數);
2)字符型:char、string;
3)布爾型:true、false;
1)顯示轉換;
2)隱式轉換;
功能:設定本地變量、定義命令別名。
profile類:為交互式登錄的用戶提供配置!
全局:/etc/profile、/etc/profile.d/*.sh
用戶:~/.bash_profile
bashrc類:為非交互式的用戶提供配置!
全局:/etc/bashrc
用戶:~/.bashrc
shell腳本第一行必須頂格寫,用shabang定義指定的解釋器來解釋該腳本。
#!/bin/bash //!即為shebang
//其它的以#開頭的行均為注釋,會被解釋器忽略,可用來注釋腳本用途及版本,方便使用管理。
bash編程屬于面向過程編程,執行方式如下:
1)順序執行:按命令先后順尋依次執行;
2)選擇執行:測試條件,可能會多個測試條件,某條件滿足時,則執行對應的分支;
3)循環執行:將同一段代碼反復執行多次,因此,循環必須有退出條件;否則,則陷入死循環;
1)bash -n SHELLNAME #語法測試,測試是否存在語法錯誤;
2)bash -x SHELLNAME #模擬單步執行,顯示每一步執行過程;
定義整型變量:
1)et VAR_NAME=INTEGER_VALUE //例如:let a=3
2)declare -i VAR_NAME=INTEGER_VALUE //例如:declare -i a=3
實現算術運算的方式:
let VAR_NAME=ARITHMATIC_EXPRESSION
VAR_NAME=$[ARITHMATIC_EXRESSION]
VAR_NAME=$((EXPRESSION))
VAR_NAME=$(expr $num1 + $num2)
算法運算符:
+:加法
-:減法
*:乘法
/:整除
%:取余數
**:乘冪
注意:即使沒有定義為整型變量,字符型的數字依然可以參與算術運算,bash會執行變量類型的隱式類型轉換。
布爾運算:真,假
與運算:真 && 真 = 真
真 && 假 = 假
假 && 真 = 假
假 && 假 = 假
或運算:真 || 真 = 真
真 || 假 = 真
假 || 真 = 真
假 || 假 = 假
非運算:!真=假
!假=真
整型測試:整數比較
例如 [ $num1 -gt $num2 ]
-gt: 大于
-lt: 小于
-ge: 大于等于
-le: 小于等于
-eq: 等于
-ne: 不等于
字符測試:字符串比較
雙目:
例如[[ "$str1" > "$str2" ]]
>: 大于則為真
<: 小于則為真
>=:大于等于則為真
<=:小于等于則為真
==:等于則為真
!=:不等于則為真
單目:
-n String: 是否不空,不空則為真,空則為假
-z String: 是否為空,空則為真,不空則假
文件測試:判斷文件的存在性及屬性等
-a FILE:存在則為真;否則則為假;
-e FILE:存在則為真;否則則為假;
-f FILE: 存在并且為普通文件,則為真;否則為假;
-d FILE: 存在并且為目錄文件,則為真;否則為假;
-L/-h FILE: 存在并且為符號鏈接文件,則為真;否則為假;
-b: 存在并且為塊設備,則為真;否則為假;
-c: 存在并且為字符設備,則為真;否則為假
-S: 存在并且為套接字文件,則為真;否則為假
-p: 存在并且為命名管道,則為真;否則為假
-s FILE: 存在并且為非空文件則為值,否則為假;
-r FILE:文件可讀為真,否則為假
-w FILE:文件可寫為真,否則為假
-x FILE:文件可執行為真,否則為假
file1 -nt file2: file1的mtime新于file2則為真,否則為假;
file1 -ot file2:file1的mtime舊于file2則為真,否則為假;
組合條件測試:在多個條件間實現邏輯運算
與:[ condition1 -a condition2 ]
condition1 && condition2
或:[ condition1 -o condition2 ]
condition1 || condition2
非:[ -not condition ]
! condition
與:COMMAND1 && COMMAND2
COMMAND1如果為假,則COMMAND2不執行
或:COMMAND1 || COMMAND2
COMMAND1如果為真,則COMMAND2不執行
非:! COMMAND
1、if語句之單分支
語句結構:
if 測試條件;then
選擇分支
fi
表示條件測試狀態返回值為值,則執行選擇分支
例:寫一個腳本,接受一個參數,這個參數是用戶名;如果此用戶不存在,則創建該用戶;
#!/bin/bash
if ! id $1 &> /dev/null;then
useradd $1
fi
2、if語句之雙分支
語句結構:
if 測試條件;then
選擇分支1
else
選擇分支2
fi
兩個分支僅執行其中之一
例:通過命令行給定一個文件路徑,而后判斷:如果此文件中存在空白行,則顯示其空白行的總數;否則,則顯示無空白行;
#!/bin/bash
if grep "^[[:space]]*$" $1 &> /dev/null; then
echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."
else
echo "No blank lines"
fi
注意:如果把命令執行成功與否當作條件,則if語句后必須只跟命令本身,而不能引用。
3、if語句之多分支
語句結構:
if 條件1;then
分支1
elif 條件2;then
分支2
elif 條件3;then
分支3
...
else
分支n
fi
例:傳遞一個用戶名給腳本:如果此用戶的id號為0,則顯示說這是管理員;如果此用戶的id號大于等于500,則顯示說這是普通用戶;否則,則說這是系統用戶。
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` username"
exit 1
fi
if ! id -u $1 &> /dev/null; then
echo "Usage: `basename $0` username"
echo "No this user $1."
exit 2
fi
if [ $(id -u $1) -eq 0 ]; then
echo "Admin"
elif [ $(id -u $1) -ge 500 ]; then
echo "Common user."
else
echo "System user."
fi
read [option] “prompt”-p:直接指定一個變量接受參數
-t timaout:指定等待接受參數的時間
-n:表示不換行
例:輸入用戶名,可返回其shell
#!/bin/bash
read -p "Plz input a username: " userName
if id $userName &> /dev/null; then
echo "The shell of $userName is `grep "^$userName\>" /etc/passwd | cut -d: -f7`."
else
echo "No such user. stupid."
fi
case語句:有多個測試條件時,case語句會使得語法結構更明晰
語句結構:
case 變量引用 in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
...
*)
分支n
;;
esac
PATTERN:類同于文件名通配機制,但支持使用|表示或者
a|b: a或者b*:匹配任意長度的任意字符
?: 匹配任意單個字符
[]: 指定范圍內的任意單個字符
例:寫一個腳本,完成如下任務,其使用形式如下所示:
script.sh {start|stop|restart|status}
其中:如果參數為空,則顯示幫助信息,并退出腳本;
如果參數為start,則創建空文件/var/lock/subsys/script,并顯示“starting script successfully.”
如果參數為stop,則刪除文件/var/lock/subsys/script,并顯示“Stop script successfully.”
如果參數為restart,則刪除文件/var/locksubsys/script并重新創建,而后顯示“Restarting script successfully.”
如果參數為status,那么:如果文件/var/lock/subsys/script存在,則顯示“Script is running…”,否則,則顯示“Script is stopped.”
#!/bin/bash
file='/var/lock/subsys/script'
case $1 in
start)
if [ -f $file ];then
echo "Script is running..."
exit 3
else
touch $file
[ $? -eq 0 ] && echo "Starting script successfully."
fi
;;
stop)
if [ -f $file ];then
rm -rf $file
[ $? -eq 0 ] && echo "Stop script successfully."
else
echo "Script is stopped..."
exit 4
fi
;;
restart)
if [ -f $file ];then
rm -rf $file
[ $? -eq 0 ] && echo "Stop script successfully"
else
echo "Script is stopped..."
exit 5
fi
touch $file
[ $? -eq 0 ] && echo "Starting script successfully"
;;
status)
if [ -f $file ];then
echo "Script is running..."
else
echo "Script is stopped."
fi
;;
*)
echo "`basename $0` {start|stop|restart|status}"
exit 2
;;
esac
1、for語句格式一
語句結構:
for 變量名 in 列表; do
循環體
done
列表:可包含一個或多個元素
循環體:依賴于調用變量來實現其變化
循環可嵌套
退出條件:遍歷元素列表結束
例:求100以內所有正整數之和
#!/bin/bash
declare -i sum=0
for i in {1..100}; do
let sum+=$i
done
echo $sum
2、for語句格式二
for ((初始條件;測試條件;修改表達式)); do
循環體
done
先用初始條件和測試條件做判斷,如果符合測試條件則執行循環體,再修改表達式,否則直接跳出循環。
例:求100以內所有正整數之和(for二實現)
#!/bin/bash
declare -i sum=0
for ((counter=1;$counter <= 100; counter++)); do
let sum+=$counter
done
echo $sum
while循環語句適用于循環次數未知,或不適用for直接生成較大的列表!
語句結構:
while 測試條件; do
循環體
done
測試條件為真,進入循環;測試條件為假,退出循環
例1:求100以內所有偶數之和,要求使用取模方法
#!/bin/bash
declare -i counter=1
declare -i sum=0
while [ $counter -le 100 ]; do
if [ $[$counter%2] -eq 0 ]; then
let sum+=$counter
fi
let counter++
done
echo $sum
例2:提示用戶輸入一個用戶名,如果用戶存在,就顯示用戶的ID號和shell;否則顯示用戶不存在;顯示完成之后不退出,再次重復前面的操作,直到用戶輸入q或quit為止
#!/bin/bash
read -p "Plz enter a username: " userName
while [ "$userName" != 'q' -a "$userName" != 'quit' ]; do
if id $userName &> /dev/null; then
grep "^$userName\>" /etc/passwd | cut -d: -f3,7
else
echo "No such user."
fi
read -p "Plz enter a username again: " userName
done
while特殊用法:遍歷文本文件
語句結構:
while read 變量名; do
循環體
done < /path/to/somefile
變量名,每循環一次,記憶了文件中一行文本
例:顯示ID號為偶數,且ID號同GID的用戶的用戶名、ID和SHELL
while read line; do
userID=`echo $line | cut -d: -f3`
groupID=`echo $line | cut -d: -f4`
if [ $[$userID%2] -eq 0 -a $userID -eq $groupID ]; then
echo $line | cut -d: -f1,3,7
fi
done < /etc/passwd
語句結構:
until 測試條件; do
循環體
done
測試條件為假,進入循環;測試條件為真,退出循環
例:求100以內所有偶數之和,要求使用取模方法(until實現)
#!/bin/bash
declare -i counter=1
declare -i sum=0
until [ $counter -gt 100 ]; do
if [ $[$counter%2] -eq 0 ]; then
let sum+=$counter
fi
let counter++
done
echo $sum
例:提示用戶輸入一個用戶名,如果用戶存在,就顯示用戶的ID號和shell;否則顯示用戶不存在;顯示完成之后不退出,再次重復前面的操作,直到用戶輸入q或quit為止(until實現)
#!/bin/bash
read -p "Plz enter a username: " userName
until [ "$userName" = 'q' -a "$userName" = 'quit' ]; do
if id $userName &> /dev/null; then
grep "^$userName\>" /etc/passwd | cut -d: -f3,7
else
echo "No such user."
fi
read -p "Plz enter a username again: " userName
done
循環控制命令:
1)break:提前退出循環;
2)break [N]: 退出N層循環;N省略時表示退出break語句所在的循環;
3)continue: 提前結束本輪循環,而直接進入下輪循環;
4)continue [N]:提前第N層的循環的本輪循環,而直接進入下輪循環;
#while體while true; do
循環體
done
#until體
until false; do
循環體
done
例1:寫一個腳本,判斷給定的用戶是否登錄了當前系統
(1) 如果登錄了,則腳本終止;
(2) 每5秒種,查看一次用戶是否登錄;
#!/bin/bash
while true; do
who | grep "gentoo" &> /dev/null
if [ $? -eq 0 ];then
break
fi
sleep 5
done
echo "gentoo is logged."
位置參數可以用shift命令左移,比如shift 3 表示原來的$4現在變成$1,原來的$5變成$2等等,原來的$1、$2、$3丟棄,$0不移動。不帶參數的shift命令相當于shift 1。
我們知道,對于位置變量或命令行參數,其個數必須是確定的,或者當shell程序不知道其個數時,可以把所有參數一起復制給“$*”。若用戶要求 Shell 在不知道位置變量個數的情況下,還能逐個的把參數一一處理,也就是在 $1 后為 $2,在 $2 后面為 $3 等。在 shift 命令執行前變量 $1 的值在 shift 命令執行后就不可用了。
實例一如下:
[root@localhost ~]# cat 1.sh
#!/bin/bash
while [ $# -ne 0 ]
do
echo "第一個參數為:$1 參數個數為:$#"
shift
done
[root@localhost ~]# sh 1.sh 1 2 3 4
第一個參數為:1 參數個數為:4
第一個參數為:2 參數個數為:3
第一個參數為:3 參數個數為:2
第一個參數為:4 參數個數為:1
從上面例子中可以看出shift命令每執行一次,變量的個數($#)減1,而變量的值提前一位。
實例二如下:
[root@localhost ~]# cat 2.sh
#!/bin/bash
if [ $# -eq 0 ]
then
echo "Usage:2.sh 參數"
exit 1
fi
sum=0
while [ $# -ne 0 ]
do
sum=`expr ${sum} + $1`
shift
done
echo "sum is:${sum}"
[root@localhost ~]# sh 2.sh 10 20 30
sum is:60
shift命令還有一個重要用途,Bash定義了9個位置變量,從$1到$9,這并不意味這用戶在命令行只能使用9個參數,借助shift命令可以訪問多于9個的參數。
shift命令一次移動到參數的個數由其所帶的參數指定,例如當shell程序處理完前9個命令行參數后,可以使用shift 9命令把$10移動到$1。
語法結構:
function F_NAME {
函數體
}
或
F_NAME() {
函數體
}
可調用:使用函數名,函數名出現的地方,會被自動替換為函數;
函數的返回值:
函數的執行結果返回值:代碼的輸出
函數中使用打印語句:echo, printf
函數中調用的系統命令執行后返回的結果
執行狀態返回值:
默認取決于函數體執行的最后一個命令狀態結果
自定義退出狀態碼:return [0-255]
注意:函數體運行時,一旦遇到return語句,函數即返回!
在函數中調用函數參數的方式同腳本中調用腳本參數的方式:
位置參數
$1, $2, …
$#, $*, $@
實例:
要求如下:
1)提示用戶輸入一個可執行命令;
2)獲取這個命令所依賴的所有庫文件(使用ldd命令);
3)復制命令之/mnt/sysroot目錄;
4)復制各庫文件至/mnt/sysroot對應的目錄中;
[root@localhost ~]# cat 1.sh
#!/bin/bash
target=/mnt/sysroot/
[ -d $target ] || mkdir $target
preCommand() {
if which $1 &> /dev/null; then
commandPath=`which --skip-alias $1`
return 0
else
echo "No such command."
return 1
fi
}
commandCopy() {
commandDir=`dirname $1`
[ -d ${target}${commandDir} ] || mkdir -p ${target}${commandDir}
[ -f ${target}${commandPath} ] || cp $1 ${target}${commandDir}
}
libCopy() {
for lib in `ldd $1 | egrep -o "/[^[:space:]]+"`; do
libDir=`dirname $lib`
[ -d ${target}${libDir} ] || mkdir -p ${target}${libDir}
[ -f ${target}${lib} ] || cp $lib ${target}${libDir}
done
}
read -p "Plz enter a command: " command
until [ "$command" == 'quit' ]; do
if preCommand $command &> /dev/null; then
commandCopy $commandPath
libCopy $commandPath
fi
exit 1
done
[root@localhost ~]# sh 1.sh
Plz enter a command: cat
[root@localhost ~]# ls /mnt/sysroot/bin/
cat
[root@localhost ~]# ls /mnt/sysroot/
bin lib64
trap命令用于在shell程序中捕捉到信號,之后可以由三種反應方式:
1)執行一段程序來處理這一信號;
2)接收信號的默認操作;
3)忽略這一信號;
示例:
寫一個腳本,能夠ping探測指定網絡內的所有主機是否在線,當沒有執行完時可接收ctrl+c命令退出。
[root@localhost ~]# cat 1.sh
#!/bin/bash
quitScript() {
echo "Quit..."
}
trap 'quitScript; exit 5' SIGINT
cnetPing() {
for i in {1..254}; do
if ping -c 1 -W 1 $1.$i &> /dev/null; then
echo "$1.$i is up."
else
echo "$1.$i is down."
fi
done
}
bnetPing() {
for j in {0..255}; do
cnetPing $1.$j
done
}
anetPing() {
for m in {0..255}; do
bnetPing $1.$m
done
}
netType=`echo $1 | cut -d"." -f1`
if [ $netType -ge 1 -a $netType -le 126 ]; then
anetPing $netType
elif [ $netType -ge 128 -a $netType -le 191 ]; then
bnetPing $(echo $1 | cut -d'.' -f1,2)
elif [ $netType -ge 192 -a $netType -le 223 ]; then
cnetPing $(echo $1 | cut -d'.' -f1-3)
else
echo "Wrong"
exit 2
fi
[root@localhost ~]# sh 1.sh 192.168.1.1
192.168.1.1 is down.
192.168.1.2 is down.
192.168.1.3 is down.
192.168.1.4 is down.
192.168.1.5 is down.
192.168.1.6 is down.
192.168.1.7 is down.
192.168.1.8 is down.
192.168.1.9 is down.
192.168.1.10 is up.
192.168.1.11 is down.
^CQuit...
看完上述內容,你們對Linux中bash編程的使用方法有進一步的了解嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注創新互聯網站建設公司行業資訊頻道,感謝各位的閱讀!
另外有需要云服務器可以了解下創新互聯建站www.yijiale78.com,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業上云的綜合解決方案,具有“安全穩定、簡單易用、服務可用性高、性價比高”等特點與優勢,專為企業上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。
網站名稱:Linux中bash編程的使用方法-創新互聯
文章轉載:http://www.yijiale78.com/article6/dociog.html
成都網站建設公司_創新互聯,為您提供小程序開發、移動網站建設、軟件開發、域名注冊、動態網站、網站設計公司
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯