下面是bash的相關內容,包括bash的顏色代碼、bash的四類文件、bash中變量處理方式、數組變量、shell的過程式編程語言以及部分簡單腳本例子。
一、bash的顏色顯示規則(顏色代碼)
bash的顏色代碼,是ASCII編碼對于顏色進行設置。顏色代碼中,字符串\033:表示Ctrl。其中,關于顏色代碼的各字符實現的功能如下:
? [ ?:控制字符和顏色代碼之間的間隔字符
? 0m:關閉顏色屬性的命令
? 1m:對于顯示的文本字符進行加粗
? 4m:為文本字符加下劃線標識
? 5m:使文本字符閃爍
? 7m:將背景色和前景色調換,白變黑,黑變白
? 8m:隱藏字符,將文本字符的背景色和前景色設置為相同顏色,同為黑或同為白
? 30m-39m:設置文本字符的前景色,即顯示什么顏色的字符,38m和39m暫時沒有用到
? 40m-49m:設置文本字符的背景色,即黑色字符后的背景是什么顏色的背景,48m和49m暫時沒有用到
示例:多個復合例子
# echo -e "\033[5;1;31;47mhello world\033[0m" 必須加-e選項,被解釋;然后加[0m退出
二、bash的四類文件
一個完整的程序,一般包括四類文件:即二進制文件(可執行文件)、頭文件庫文件、幫助文件、配置文件。bash是一個接口程序,是命令行接口(CLI)的一種,所以也包括該四類。
shell有兩種類型,即交互式登錄的shell和非交互式登錄的shell,具體解釋如下:
? ?(1)、交互式登錄的shell:直接通過某個終端輸入賬號和密碼后登錄打開的shell進程;使用su - USERNAME或su -l USERNAME執行切換登錄打開的shell進程
? ?(2)、非交互式登錄的shell:在圖形界面下,通過菜單或右鍵菜單打開的終端的shell進程;使用su USERNAME執行切換登錄打開的shell進程
在bash中,# file /bin/bash 用來查詢文件,/usr/include/下有庫文件,/usr/share/下有幫助文件,例:# ls /usr/share/man/man1
?bash有三類配置文件:(1)、profile類:為交互登錄的shell進程實現功能初始化的配置文件;(2)、bashrc類:為非交互登錄的shell進程實現功能啟動配置的配置文件;(3)、logout類:為交互式登錄的shell進程提供終止即清理類功能的配置文件
?1、profile類
?在RHET或Centos的操作系統中,通常情況下,一個配置文件的內容很多,格式復雜,我們會將其切換為多個片段,將切割出來的片段統一存放在“程序名稱.d”的文件中,在這樣的目錄中所保存的片段文件,大多以統一的文件后綴名來命名。
? profile類分為全局和用戶個人兩種,具體解釋如下:
? ? 全局(profile類):對所有用戶都生效的配置文件,有 /etc/profile 和 /etc/profile.d/*.sh
? ? 用戶個人(profile類):僅僅只是針對某個用戶有效的配置文件,有 ~/.bash_profile
?profile類配置的文件有兩個作用:即用于定義用戶的環境變量;用于運行腳本或執行命令。
?2、bashrc類
? bashrc類也分為全局和用戶個人兩種,具體解釋如下:
? ? ?全局(bashrc類):有 /etc/bashrc
? ? ?用戶個人(bashrc類):有 ~/.bashrc
?bashrc類配置的文件有三個作用:即用于定義本地變量;用于定義命令的別名;定義umask
?注意:只有超級用戶root才可以修改全局類的配置文件,而普通用戶只能修改其家目錄中的個人配置文件
?3、logout類
登錄進程加載配置文件的順序可以如下:
? 交互式登錄的shell進程,會按照順序加載下列配置文件:/etc/profile--->/etc/profile.d/*.sh---->~/.bash_profile--->~/.bashrc----->/etc/bashrc
? 非交互式登錄的shell進程,會按照順序加載下列配置文件: ~/.bashrc----->/etc/bashrc---->/etc/profile.d/*.sh
所有在命令行中執行的命令操作,只要沒涉及到文件的修改的,一般都只是針對當前的shell生命周期有效;只要shell進程結束,所有的設置均失效。配置文件的作用如下:使得我們賴以生存的配置信息可以長期有效,只要不修改配置文件中的內容,每一次打開shell都會使曾經的配置生效。
讓配置文件中的新定義的配置能夠立即生效的方式有source命令和exec命令兩種,具體解釋如下:
? 1、source命令:把shell的內容在當前命令中運行。具體命令如下兩種:
? ? ?source /PATH/TO/SOME_CONF_FILES
? ? ?. /PATH/TO/SOME_CONF_FILES
? 2、exec命令:使用指定命令來替換shell。具體命令如下:
? ? ?exec /PATH/TO/SOME_CONF_FILES
?
?三、bash中變量處理方式
?變量是內存中的一段存儲空間。其中的弱變量,無需事先定義即可使用;沒有變量數據類型的硬性要求,默認是字符型。
?bash中變量存放的7種字符串內容處理方式如下(處理時其值沒有變,而只是執行時改變):
? 1、字符串切片
? ? ${#VAR}:返回字符串類型的變量VAR的長度
? ? ${VAR:offset}:返回字符串變量VAR中第offset個字符后面的內容,不包括offset這個字符,offset的取值范圍為:0-$[$(#VAR)-1]
? ? ${VAR:offset:number}:返回字符串變量VAR中第offset個字符后開始,長度為numer的字符部分
? ? ${VAR: -length}:取字符串最右側的length個字符,從右向左選擇
? 2、基于模式取字串
? ? ${VAR#*PATTERN}:自左而右,查找VAR變量所存儲的字符串中,第一次被PATTERN匹配的字符,刪除從字符串開始到PATTERN匹配的字符之間的所有字符(可以取基名)-----留后面
? ? ${VAR##*PATTERN}:自左而右,查找VAR變量所存儲的字符串中,所有被PATTERN匹配的字符,刪除從字符串開始到最后一個PATTERN匹配的字符?
? ? ${VAR%PATTERN*}:自右而左,查找VAR變量所存儲的字符串中,第一次被PATTERN匹配的字符,刪除從字符串開始到PATTERN匹配的字符之間的所有字符(可以取目錄名)------留前面
? ? ${VAR%%PATTERN*}:自右而左,查找VAR變量所存儲的字符串中,所有被PATTERN匹配的字符,刪除從字符串開始到最后一個PATTERN匹配的字符之間的所有字符
? 3、查找替換
? ? ${VAR/PATTERN/SUBSTRING}:在VAR變量中查找匹配PATTERN的內容,將其第一個匹配到的結果更換成SUBSTRING
? ? ${VAR//PATTERN/SUBSTRING}:在VAR變量中查找匹配PATTERN的內容,將其所有匹配到的結果更換成SUBSTRING
? ? ${VAR/#PATTERN/SUBSTRING}:在VAR變量中查找 行首 匹配PATTERN的內容,將匹配到的結果更換成SUBSTRING
? ? ${VAR/%PATTERN/SUBSTRING}:在VAR變量中查找 行尾 匹配PATTERN的內容,將匹配到的結果更換成SUBSTRING
? 4、查找刪除
? ? ${VAR/PATTERN}:在VAR變量中查找匹配PATTERN的內容,將其第一個匹配到的結果刪除
? ? ${VAR//PATTERN}:在VAR變量中查找匹配PATTERN的內容,將其匹配到的結果刪除
? ? ${VAR/#PATTERN}:在VAR變量中查找匹配PATTERN的內容,將其 行首 匹配到的結果刪除
? ? ${VAR/%PATTERN}:在VAR變量中查找匹配PATTERN的內容,將其 行尾 匹配到的結果刪除
? 5、字符的大小寫轉換
? ? ${VAR^^}:將VAR變量中的所有小寫字母轉換為大寫字母
? ? ${VAR,,}:將VAR變量中的所有大寫字母轉換為小 寫字母
? 6、變量賦值
? ? ${VAR:-value}:如果變量為空或未被設置,那么直接返回value值,否則返回變量VAR的值
? ? ${VAR:+value}:如果變量不為空,那么直接返回變量VAR的值,否則返回value值
? ? ${VAR:=value}:如果變量為空或未被設置,那么直接返回value值,并且將value值賦值給變量VAR,否則返回變量VAR的值
? 7、變量的間接引用
? ? 如果第一個變量的值是第二個變量的變量名,從第一個變量引用第二個變量的值的方法,就稱為變量的間接引用,也稱為間接變量引用。例如:VAR1=VAR2 VAR2=value
? ? bash提供的兩種格式的間接變量的引用方式:(1)、eval MYVAR=\$$VAR1 相當于 MYVAR=value ; (2)、MYVAR=${!VAR1}
四、數組變量
?變量為內存中的存儲空間。變量的特點為,每個變量中只能存放一個數據,即變量只能進行一次性的賦值,否則被覆蓋。
?示例:存放本班每個人的名字于變量,三種賦值方式如下:
? (1)、一次性賦值:ANME="name1 name2 name3……"
? (2)、使用多個變量分別賦值:NAME1=little1 NAME2=little2 NAME3=little3 ……
? (3)、使用數組變量
1、數組的組成部分
?數組變量:相似屬性的數據組,存放一個或多個元素的連續內存空間(當然也可以有空數組),相當于多個變量的集合。
?數組元素:數組中任何一個存放數據的存儲單元
?數組的索引包括兩部分:
? (1)、數字:索引數組(index array)例 0,1,2,3,4,5,……?
? (2)、名稱(字符串):關聯數組(related array) ; 但是只有bash4.0以上的版本才支持關聯數組
2、數組的分類
?數組分為稠密數組和稀疏數組。稠密數組,其索引編號必須連續;稀疏數組,其索引編號可以不連續,bash數組屬于此類稀疏數組。
3、聲明數組
? (1)、declare命令?
? ?declare -i NAME:將NAME聲明為整形變量
? ?declare -x NAME:將NAME聲明為環境變量
? ?declare -a NAME:將NAME聲明為索引數組(版本支持時可以用)
? ?declare -A NAME:將NAME聲明為關聯數組(版本支持時可以用)
? ?示例:declare -a NAME=("value1" "value2" "value3" ……)
? ? ? ? ?declare -a NAME=([0]="value1" [1]="value2" [6]="value3" ……)?
? (2)、直接聲明數組
? ? ARRAY_NAME=("value1" "value2" "value3" ……) ?即聲明稠密數組——直接為數組賦值
? ? ARRAY_NAME=([0]="value1" [1]="value2" [6]="value3" ……) ?即聲明稀疏數組
? (3)、定義數組的元素而創建的數組
? ? ARRAY_NAME[0]=value1 ??
? ? ARRAY_NAME[1]=value2?
? ? …… ?
4、引用數組中的元素:
? 引用變量的方法:${NAME}
? 引用數組元素的方法:${ARRAY_NAME[INDEX]}?
? ? 注意:如果不給出INDEX,則表示引用數組的第一個元素,即INDEX=0的元素
? 引用整個數組的所有元素的索引號:${!ARRAY_NAME[*]}或者${!ARRAY_NAME[@]}?
? 引用整個數組的所有元素:${ARRAY_NAME[*]}或者${ARRAY_NAME[@]}?
5、查找數組的長度(數組中有效元素的個數)
? ${#ARRAY_NAME[*]}?
? ${#ARRAY_NAME[@]}?
6、數組切片
? ${ARRAY_NAME:offset}:顯示包括offset ?例:${ARRAY_NAME:6}:跳過0-5,從6開始,跳過了6個
? ${ARRAY_NAME:offset:number}:顯示包括offset數組所代表的索引位置及以后的number個元素 ?
? 示例:${ARRAY_NAME:6:3}:跳過0-5,從6開始,顯示6、7、8,其中跳過了6個。
7、向數組中追加元素:
? 稠密數組追加:ARRAY_NAME[${#ARRAY_NAME[*]}]=valueN
? 稀疏數組追加:ARRAY_NAME[INDEX]=valueN 注意:稀疏數組追加的INDEX必須為未被使用的數組元素的索引編號
8、撤銷數組:usnet ARRAY_NAME
9、刪除數組中的元素:usnet ARRAY_NAME[INDEX]
? RANDOM變量:隨機數變量,0-32767(2^15-1)
五、bash腳本編程
示例1、寫一個腳本:創建一個用戶little,如果用戶已經存在,就提示用戶已經存在的信息,否則將創建用戶
# id little &> /dev/null && echo 存在 || useradd little
1、shell腳本編程的特點:過程式編程語言、腳本類語言、解釋型語言。
?過程式編程語言包括3種基本結構,順秀執行結構、選擇執行結構和循環執行結構,具體解釋如下:
?順秀執行結構:以從左到右,從上到下順序執行所有語句(命令),順序執行結構是shell腳本的主體結構
?選擇執行結構:依照給定條件的邏輯判斷結果依照可選的取值范圍,進而選擇某個分支中的語句來執行。具體有if和case兩種分支結構,即if的分支選擇標準,是邏輯判斷的結果;case的分支選擇標準,是根據可選的取值。
?循環執行結構:對于某特定語句,重復執行n次。具體有for、while、until、select,解釋如下:
? ?for:遍歷指定的列表,列表必須事先存在,大規模不建議使用
? ?while:根據邏輯判斷的結果判斷是否進入循環
? ?until:根據邏輯判斷的結果判斷是否進入循環
? ?select:永遠的死循環,不給命令退出就一直執行
?
?2、選擇執行結構:
? if語句:if是shell的關鍵字,不允許有別名
? 格式:if 命令; then 命令;[elif 命令; then 命令]……[else 命令;] fi?
? if語句的2種單分支結構表達格式如下:
? if CONDITION
? then statement
? fi
? if CONDITION;then?
? statement1
? statement2
? ……
? fi
? ? 注意:想要執行then后面的statements,前提條件是CONDITION部分為真
? if語句的雙分支結構:如果條件為真,就執行then后面的命令;否則就執行else后面的命令
? ? if CONDITION;then
? ? ? ?statement
? ? ? ?……
? ? else
? ? ? ?statement
? ? ? ?……
? ? fi
? if語句的多分支結構:首先判斷CCONDITION1是否為真,如果為真,則執行第一個then后面的語句;否則判斷CONDITION2是否為真,如果為真,則執行第2個then后面的語句……
? ? if CONDITION1;then
? ? ? ?statement
? ? ? ?……
? ? elif CONDITION2;then
? ? ? ?statement
? ? ? ?……
? ? elif CONDITION3;then
? ? ? ?statement
? ? ? ?……
? ? fi
?示例2:寫一個腳本,列出系統中默認shell的bash用戶
?#!/bin/bash
?#
?if grep -q "bash$";then
? ? grep ?"bash$" | cut -d: -f1
?fi?
3、bash腳本之間的用戶交互
?bash腳本的位置參數變量為:$1、$2、$3、……
?bash腳本的特殊變量為:
? ?$# :所有的位置參數的總數
? ?$* :給出的所有位置參數的列表,當使用雙引號引用時,整個參數列表被當做一個字符串
? ?$@ :給出的所有位置的參數列表,當使用雙引號引用時,每個參數作為單獨的字符串存在
? ?$0 :所執行的腳本文件自身的路徑
示例3:創建一個用戶,如果用戶已經存在,就提示用戶已經存在的信息,否則將創建用戶
#!/bin/bash
#
if id $1 &> /dev/null;then
? echo "$1 存在"
else
? useradd $1
fi
示例4:寫一個腳本,給腳本傳遞用戶名參數,判斷參數數量是否合格,并且判斷用戶是否存在,如果存在,就顯示相應信息,否則就創建之并為其設置密碼
#!/bin/bash
#
if [ $# -ne 1 ];then
? echo "Only ONE USERNAME can be spacified."
? exit 5
fi
if id $1 &> /dev/null ; then
? echo "$1 exists already."
else?
? useradd $1
? echo $1 | passwd --stdin $1 &> /dev/null
? echo "create $1 successfully."
fi
4、read命令:read是bash的內置命令
? 格式:read [-a 數組] [-p 提示符] [-t 超時] ?[名稱 ……] ?
? read格式中的[名稱]:一般為變量名或者數組名,如果不寫名稱,則系統會將read讀到的信息保存在REPLY變量中
示例5:# read -p "Please enter some username: " NAME1 NAME2 NAME3 回車后輸出:Please enter some username: little1 little2 little3
?注意:read可以使用戶與shell進行交互,在使用read命令的時候,通常會使用-t選項規定超時時間,一旦使用-t選項定義了超時時間,我們必須在后面判斷給定的變量是否為空,如果為空則需要為變量名提供默認值
示例6:寫一個腳本,能夠添加或刪除用戶賬戶,可以使用-a選項完成添加,使用-d選項完成刪除任務
#!/bin/bash
#
if [ $# -ne 2 ] ; then?
? echo "usage: $(basename $0) -a useranme | -d username."
? exit 5
fi
if [ $1 == '-a' ] ; then?
? if id $2 &> /dev/null ; then?
? ? ?echo "$2 exits already."
? else?
? ? ?useradd $2
? ? ?echo $2 | passwd --stdin $2 &> /dev/null
? ? ?echo "create $2 successfully."
? fi
fi
if [ $1 == '-d' ] ; then?
? if id $2 &> /dev/null ; then
? ? userdel -r $2
? ? echo "delete $2 finished."
? else
? ? echo "user $2 does not exit."
? fi
fi
示例7:判斷給出的文件大小是否大于100kb,如果大于100kb,就顯示這是個大文件,否則就顯示這是一個小文件
#!/bin/bash?
#
filesize=$(wc -c < $1)
if [ $filesize -gt 102400 ] ; then
? echo "Big file."
else?
? echo "Small file."
fi
示例8:判斷給出的一個字符串是否為整數
#!/bin/bash
#
if echo $1 | grep "^\<[[:digit:]]\+\>$" &> /dev/null ; then?
? ?echo "$1 is integer."
else
? ?echo "$1 is not integer."
fi
5、shift命令(完成位置參數的遷移)
?shift的格式:shift [n]?
示例9:示例6的擴展,用shift實現:寫一個腳本,能夠添加或刪除用戶賬戶,可以使用-a選項完成添加,使用-d選項完成刪除任務
#!/bin/bash
#
if [ $# -ne 2 ] ; then?
? echo "usage: $(basename $0) -a useranme | -d username."
? exit 5
fi
if [ $1 == '-a' ] ; then?
? shift
? if id $1 &> /dev/null ; then?
? ? ?echo "$1 exits already."
? else?
? ? ?useradd $1
? ? ?echo $1 | passwd --stdin $1 &> /dev/null
? ? ?echo "create $1 successfully."
? fi
fi
if [ $1 == '-d' ] ; then?
? shift
? if id $1 &> /dev/null ; then
? ? userdel -r $1
? ? echo "delete $1 finished."
? else
? ? echo "user $1 does not exit."
? fi
fi
示例10:簡易計算器
#!/bin/bash
#
echo $[$1$2$3]
引用:# ./little.sh 3 + 5 ?輸出8 (3個輸入)
6、if語句的多分支結構:
if CONDITION1;then
? ? ? ?statement
? ? ? ?……
? ? elif CONDITION2;then
? ? ? ?statement
? ? ? ?……
? ? elif CONDITION3;then
? ? ? ?statement
? ? ? ?……
? ? else
? ? ? ?statement
? ? ? ?……
? ? fi
示例11:編寫一個腳本,要求:從/etc/passwd中UID和GID相同的用戶中隨機選擇一個用戶,判斷其用戶的類型:UID為0,即超級用戶;UID在1-999之間,即系統用戶;UID為1000+,即登錄用戶。
#!/bin/bash
#
LINES=$(egrep "\<([[:digit:]]+)\>.*\1" /etc/passwd | wc -l)
SEQUENCE=$[${RANDOM}%${LINES}+1]?
USERNAME=$(egrep "\<([[:digit:]]+)\>.*\1" /etc/passwd | head -n $SEQUENCE | tail -1 | cut -d: -f3)
if [ $USERID -eq 0 ] ; then
? echo "$USERNAME is super user."
elif [ $USERID -ge 1000 ] ; then
? echo "$USERNAME is login user."
else?
? echo "$USERNAME is system user."
fi
7、循環執行結構
?循環執行結構,就是將一段代碼循環的執行0次、1次或多次。一個好的循環結構,必須包含兩個重要的環節,進入循環的條件和退出循環的條件;進入循環的條件,即開始循環時所滿足的條件;退出循環的條件,即循環結束所滿足的條件
?(1)、for循環:
? for循環的遍歷列表格式:
? for VAR_NAME in LIST ; do 循環體; done
? for VAR_NAME in LIST ; do?
? ? ? 循環體;
? done
? for格式中的各個解釋如下:
? VAR_NAME :任意指定的變量名稱,變量的值是從LIST中取值并賦值的
? 循環體:能夠用到VAR_NAME的命令或目錄的組合;如果循環體中,沒有包括變量內容VAR_NAME,則可能出現死循環
? LIST的生成方式很多,具體如下:
? ?1)直接給出;
? ?2)純整數列表:seq:輸出一個純整數列表 ?seq [FIRST [INCREMENT]] LAST 例:sqe 1 2 10(輸出奇數,2表示增量)
? ?3)花括號展開:{FIRST..LAST} 例如:echo {1..100} ; echo {a..z} ; echo {A..Z}
? ?4)命令的執行結果的返回值
? ?5)GLOBBING
? ?6)某些變量的引用: $@ ?$*
示例12:寫一個腳本,能夠添加或刪除一個或多個用戶賬戶,可以使用-a選項完成添加,使用-d選項完成刪除任務
#!/bin/bash
#
if [ $# -lt 2 ] ; then
? echo "Usage: $(basename $0) -a User1 User2 ... | -d User1 User2 ..."
? exit 5
fi
if [ $1 == '-a' ] ; then
? shift
? for I in $* ; do
? ? if id $I &> /dev/null ; then
? ? ? echo "$I exists already."
? ? else
? ? ? useradd $I
? ? ? echo $I | passwd --stdin $I &> /dev/null
? ? ? echo "Create $I successfully."
? ? fi
? done
fi
if [ $1 == '-d' ] ; then
? shift
? for J in $* ; do
? ? if id $J &> /dev/null ; then
? ? ? userdel -r $J
? ? ? echo "Delte $J finished."
? ? else
? ? ? echo "User $J does not exist."
? ? fi
? ? done
fi
8、for循環的優勢及特點
? for循環:進入循環條件,LIST中有元素可以取用;退出循環條件,LIST中被取空,再無元素可用
? for循環的特點:1、幾乎不會出現死循環;2、在執行循環的過程中,需要將這個LIST載入內存,因此,對于大列表來說,可能會過多的消耗內存和CPU資源
? 注意:使用for循環嵌套的時候,外層for循環,控制行數的輸出;內層for循環,控制列數的輸出
示例13:計算100以內所有整數的和
#!/bin/bash
#
read -t 5 -p "Please input a integer[0]: " INTEGER
if [ -z $INTEGER ] ; then
? INTEGER=0
fi
if ! echo $INTEGER | grep -q "^\<[[:digit:]]\+\>$" ; then
? echo "You must input an integer."
? exit 5
fi
for I in $(seq $INTEGER) ; do
# let SUM+=$I
# let SUM=$SUM+$I
? SUM=$[SUM+I]
done
echo $SUM
100以內的也可以為:for I in {1..100} ; do for I in {seq $1} ; done
示例14:寫一個腳本,打印倒置的等腰三角形。每行星星個數公式:2*[n-($n-1)]-1 ; 2*(總行數-第幾行)+1
********* ? 1 ?0 ?9 ? 行-1個空格 以及 2*(總行數-行)+1 個星星?
?******* 2 ?1 ?7
? ***** 3 ?2 ?5
? ?*** 4 ?3 ?3
? ? * 5 ?4 ?1
#!/bin/bash
#
LINENUM=$1
for I in $(seq $LINENUM) ; do
? for J in $(seq $[I-1]) ; do
? ? echo -n " "
? done
? for K in $(seq $[2*(LINENUM-I)+1]) ; do
? ? echo -n "*"
? done
? echo
done ??
示例15:打印九九乘法表
#!/bin/bash
#
for I in {1..9} ; do
? for J in $(seq $I) ; do
? ? echo -ne "$I*$J=$[I*J]\t"
? done
? echo
done
1X1=1 1X2=2 1X3=3 ... 1X9=9
2X2=4 2X3=6 ... 2X9=18
...
9X9=81
?2、控制變量
?for ((表達式1; 表達式2; 表達式3)); do 命令; done
?for ((表達式1; 表達式2; 表達式3)); do
? ?循環體
?done
?表達式1:為變量賦初始值
?表達式2:循環的退出條件
?表達式3:變量值的變化規律
示例16:# for ((I=1; I<=100; I++)); do let SUM+=$I; done
#!/bin/bash
for (( I=1; I<=100; I++ )); do
let SUM+=$I
done
echo $SUM