1.1 開頭(環境使用shebang機制)
#!/bin/bash 必須寫在檔案首行
符号#!用來告訴系統它後面的參數是用來執行該檔案的程式。
當編輯好腳本時,如果要執行該腳本,還必須使其可執行。
要使腳本可執行:
編譯 chmod +x filename 這樣才能用./filename或source filename 來運作。
1.2 注釋
在進行shell程式設計時,以#開頭的句子表示注釋,直到這一行的結束。我建議在程式中使用注釋。如果使用了注釋,那麼即使相當長的時間内沒有使用該腳本,我們也能在很短的時間内明白該腳本的作用及工作原理。
1.3格式

腳本中如果有文法錯誤可以用來: bash -n /path/to/some_script
調試跟蹤: bash -x /path/to/some_script
第一行的#!/bin/bash是聲明這個腳本使用的shell格式,因為我們使用的是bash,是以必須要以“#!/bin/bash”來告訴别人這個腳本裡的文法使用的是bash文法,這樣它在執行的時候,就能加載bash相關配置檔案,使我們的指令能夠更好的執行下去。(如果不加,有可能腳本無法執行,無法判斷腳本是使用的什麼shell。當然如果預設選擇bash格式,可以不寫,但最好還是腳本第一行寫上shebang機制,還有就是建立文本的時候,字尾加上.sh為結尾。
2.1 變量定義
所有的變量都由字元串組成,用一個字元串,替代更多更複雜的内容 ,并且您不需要對變量進行聲明。在變量使用指令時需要加` ` 或者$( ).
指派給一個變量,并列印出内容如下:
有時候變量名很容易與其他文字混淆,比如:
num=2 echo “this is the $numnd” 這并不會列印出“this is the 2nd”,而僅僅列印”this is the “,因為shell會去搜尋變量numnd的值,但是這個變量時沒有值的。可以使用花括号來告訴shell我們要列印的是num變量:echo “this is the ${num}nd” 這将列印:this is the 2nd。 注意:變量名外面的花括号是可選的,加不加都行,加花括号是為了幫助解釋器識别變量的邊界
2.2 變量格式
1、必須以字母開頭後面可以使用下劃線,數字
2、中間不能有空格,不能使用标點符号,不能使用程式中的保留字如:if,for。
3、駝峰文法:首個字母小寫,其餘開頭字母大寫如 mageJiaoYu
2.3變量分類
本地變量,環境變量,位置變量,特殊變量
變量指派:name=‘value’
可以使用引用value:
(1)可以是直接字串; name=“root”
(2)變量引用:name=”$USER”
(3)指令引用:name=`COMMAND`, name=$(COMMAND)
變量引用:${name}, $name
" ":弱引用,其中的變量引用會被替換為變量值”;
例:[root@localhost ~]# var1=1 [root@localhost ~]# echo "$var1 * '' \$a\\ 1 * $a\ (雙引号比起單引号比較有人情味,也比較聰明,它能識别裡面的變量,不會屏蔽\和$這兩個字元的含義,如果需要屏蔽這些字元含義,除了用單引号外,還可以在前面加個\符号。)
' ':強引用,其中的變量引用不會被替換為變量值,而保持原字元串;
例:[root@localhost ~]# var1=2 [root@localhost ~]# echo '$var1 * \$a\\' $var1 * \$a\\ (單引号可以屏蔽全部字元的特殊意義,但是不能表示一個字元:(單引号')。由于她沒有轉義字元,是以不能表示她本身。強引用)
顯示已定義的所有變量:set
删除變量:unset name 腳本運作完畢要釋放變量。
變量聲明、指派:
export name=VALUE
declare -x name=VALUE
變量引用:$name, ${name}
删除變量:unset name
顯示所有環境變量(環境變量的查詢):
env
printenv
export
declare -x
#env列出環境下所有環境變量與其内容
#set可檢視所有的變量(含環境變量與本地變量)
bash内建的環境變量:PATH SHELL UID HOME PWD LANG MAIL HOSTNAME HISTSIZE PS1等
例:[root@centos7 ~ ]# echo $HOME [root@centos7 ~]# /root
$1, $2, …:對應第1、第2等參數,shift [n]換位置。當位置參數遇到10及10以上的要用{ };例:echo 10st 結果為arg is {10}。
$0:指令本身,是用于取腳本本身的名字
[root@centos7 tmp]# vim file1 #!/bin/bash dirname $0 basename $0 [root@centos7 tmp]# bash ./file1 . file1 [root@centos7 tmp]# bash /tmp/file1 /tmp
$#:傳遞給腳本的參數的個數,一般用于控制參數個數。
[root@centos7 tmp]#vim file2 echo $# [root@centos7 tmp]# bash file2 123 3 [root@centos7 tmp]# bash file2 123456 6
$?:判斷上個指令腳本,函數是否執行成功,指令執行的傳回值,0表示沒有錯誤,其他表示有錯誤,代表上個指令執行失敗
[root@centos7 tmp] # ls file1 file2 [root@centos7 tmp] # echo $? [root@centos7 ~] # lls bash:lls:command not found... [root@centos7 ~] # echo $? 1
$*:傳遞給腳本的所有參數,全部參數合為一個字元串
$@:傳遞給腳本的所有參數,每個參數為獨立字元串
$@ $*隻在被雙引号包起來的時候才會有差異
set —清空所有位置變量
小總結:變量内容若有空格符可使用雙引号" "或者單引号' '将變量内容結合起來:
a.雙引号内的特殊字元如$等,可以保持原本的特性,如:
b.單引号内的特殊字元則僅為一般字元(純文字),如:
c.可用轉義字元“\”将特殊符号(如$、\、!)變成一般字元。如
d.在一串指令中,還需要通過其他的指令提供的資訊,可以使用反單引号“`指令`”或者“$(指令)”,如:
e.若該變量為了增加變量内容時,則可用“$變量名稱”或${變量}累加内容,如:給變量PATH增加内容,不能直接用”PATH=内容“,這樣會覆寫掉原本的變量值,應該用“PATH=$PATH:内容”.
f.若該變量需要在其他子程序(子程序:在目前這個shell的情況下,去打開另一個新的shell,新的shell就是子程序)執行,則需要以export來使變量變成環境變量。如:
g.取消變量的方法為使用“unset變量名稱”,如:
3.1按生效範圍劃分,存在兩類:
全局配置:/etc/profile /etc/profile.d/*.sh /etc/bashrc
個人配置:~/.bash_profile ~/.bashrc
3.2按功能劃分,存在兩類:
profile類和bashrc類
profile類:為互動式登入的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
個人:~/.bash_profile
功用:(1)用于定義環境變量 (2)運作指令或腳本
bashrc類:為非互動式和互動式登入的shell提供配置
全局:/etc/bashrc
個人:~/.bashrc
功用:(1)定義指令别名和函數 (2)定義本地變量
3.3shell登入兩種方式
互動式登入:(不能繼承上一個shell)
(1)直接通過終端輸入賬号和密碼登入
(2)使用“su -l UserName 或su - UserName”切換的使用者
執行順序:/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile–> ~/.bashrc–> /etc/bashrc
非互動式登入:(繼承上一個shell)
(1)su UserName
(2)圖形界面下打開的終端,執行腳本
執行順序:~/.bashrc–> /etc/bashrc–> /etc/profile.d/*.sh
例子:在這幾個檔案分别設定環境變量A,B,C,D,E
沒有重新登陸時,這幾個變量就不會生效,echo $A $B $C $D $E,什麼都不顯示。重新登陸後,這幾個變量就會生效。
用非互動式登陸guanyu使用者,就會繼承上一個shell,是以echo 5個變量都會顯示。而用互動式登陸guanyu使用者,不能繼承上一個shell,就隻能讀取/etc/profile,/etc/profile.d/*.sh,~/.bash_profile,~/.bashrc,/etc/bashrc這幾個檔案,而變量C,D都是在使用者root的家目錄設定的,隻能讀取到變量A,B,E,是以echo這幾個變量隻顯示變量A,B,E的值。
在root使用者下,将變量A的值改為A6,變量B的值改為B7,變量D的值改為D9,變量E的值改為E10
然後不退出重新登陸,直接echo這幾個變量,當然不變,因為這幾個變量沒有生效,此時用非互動式登陸切到guanyu使用者下,變量A的值不變,盡管,變量A的值變為A6,但是用非互動式登陸,繼承了上一個shell變量A的值A1,但是不讀取/etc/profile這個檔案,是以不更新變量A的值,變量B的值變為B7,是因為繼承了上一個shell變量B的值然後讀取/etc/profile.d/mage.sh這個檔案,更新變量B的值。變量C3的值不變,變量D的值為D4,是因為繼承了上一個shell的變量D的值D4,又因為變量D在root使用者的家目錄裡,是以不讀取,不更新變量D的值。變量E5的值為E10,是因為繼承了上一個shell的變量D的值,又讀取/etc/bashrc是以更新變量E的值,是以變量E的值為E10.
在用互動式登陸guanyu使用者,echo這幾個變量,不繼承上一個shell,隻讀取檔案,因為是互動式登陸,是以/etc/profile,/etc/profile.d/mage.sh,/etc/bashrc這幾個檔案都能讀取,是以變量A,B,E的值為A6,B7,E10,又因為變量C,D都在root使用者的家目錄裡,是以不能讀取,變量C,D的值為空。
3.4 read
變量的定義—read讀入 預設存儲位置$REPLY
如果傳的參數多于指派,最後一個值會全部接收
–p增加提示
[root@centos7 ~]# read -p "輸入密碼" e (必須有空格) 輸入密碼123456 [root@centos7 ~]# echo $e 123456
–s 隐藏輸入
[root@centos7 ~]# read -s -p "輸入密碼" e (将密碼隐藏) 輸入密碼
-t 設定逾時時間
[root@centos7 ~]# read -t5 -p "輸入密碼" e (表示5秒後直接退出目前操作) 輸入密碼[root@centos7~]#
4.1條件判斷
[root@centos7 ~]# [ -f /etc/hosts ] 判斷是否是檔案 [root@centos7~]# echo $?
4.2 && ||
&&表示前面執行成功,執行後面.
||表示前面執行成功,不執行後面,前面執行失敗,執行後面
[root@centos7 ~]# [ -f /etc/hosts ]&& echo "檔案存在" || echo "檔案不存在" 相當于傳回值0和1 檔案存在
[root@centos7 ~]# [ -f /etc/host ]&& echo "檔案存在" || echo "檔案不存在" 檔案不存在
4.3 測試檔案符号(test)
4.4 測試字元串
特别注意:字元串必須要用雙引号引起來。字元串比較,比較符号兩端必須有空格。
4.5測試大小
[root@centos7 ~]# [ 1 -eq 1 ] && echo "表達式成立" || echo "表達式不成立" 表達式成立 [root@centos7 ~]# [ 1 -eq 2 ] && echo "表達式成立" || echo "表達式不成立" 表達式不成立
[root@centos7 ~]# [ 1 -ne 2 ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ 1 -gt 2 ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ 1 -gt 0 ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ 1 -gt 1 ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ 1 -ge 1 ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ 1 -le 1 ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ 1 -lt 1 ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ 1 -lt 2 ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ 1 = 1 ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ 1 = 2 ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ "1" = "2" ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ "1" != "2" ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ "1" > "2" ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ "1" \> "2" ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ "1" \< "2" ] && echo "表達式成立" || echo "表達式不成立" [root@centos7 ~]# [ "1" \<= "2" ] && echo "表達式成立" || echo "表達式不成立" -bash: [: <=: binary operator expected [root@centos7 ~]# [ "1" \<\= "2" ] && echo "表達式成立" || echo "表達式不成立"
4.6 與或非 -a -o !
-a 前一個條件成立,後一個條件成立,整個表達式才成立,有一個是錯的都不會成立
-o 隻要任意一個條件成立,表達式就成立,隻有倆個都不成立,才不成立,則表達式不成立
[root@centos7 ~]# [ "1" = "1" -a "2" = "2" ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ "1" = "1" -a "2" = "3" ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ "1" = "1" -o "2" = "3" ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ "1" = "2" -o "2" = "3" ] && echo "表達式成立" || echo "表達式不成立"
[root@centos7 ~]# [ "1" = "1" -a !"2" = "3" ] && echo "表達式成立" || echo "表達式不成立" -bash: !"2": event not found
[root@centos7 ~]# [ "1" = "2" -o ! "2" = "3" ] && echo "表達式成立" || echo "表達式不成立"
if 語句 單分支語句
文法格式:
如果if [條件語句]
然後 then
執行指令
fi
執行個體:編寫一個腳本/root/bin/createuser.sh,腳本的執行文法必須是:createuser.sh -u username -m password,選項與參數間可支援多空格,但不能順序颠倒。
當未指定正确的選項或參數時,以錯誤輸出方式提示“createuser.sh -u username -m password ”後退出腳本。
使用者名必須以字母開頭,可包括數字和_。否則不合法。以錯誤輸出提示使用者"使用者名僅包含字母資料和下劃線"
當使用者名檢測合法後,判斷使用者名是否已存在,若存在,再判斷使用者是否已設定過密碼,若設定過密碼,直接退出,未設定,則将密碼設定為所指定的密碼後以正确輸出方式顯示“username 密碼已更新後退出”
當使用者名不存在,則建立使用者,并為該使用者設定所指定的密碼後以正确輸出方式顯示“使用者username已建立并更新密碼”
要求腳本執行過程中不能有非要求的其他輸出結果出現。腳本在非正确方式退出時應反回給?參數非0值。
#判斷使用者名是否規範,并且給出傳回值
decide=`(echo $2|grep "^[[:alpha:]]\([[:alpha:]]\|[[:digit:]]\|_\)*$" &>/dev/null;echo $?)`
#判斷使用者是否存在,并給出傳回值
id=`id $2 &>/dev/null;echo $?`
#截取使用者密碼位
mima=`getent shadow $2 |cut -d: -f 2`
#判斷第一個參數
if [ "$1" != "-u" ];then
echo "createuser.sh -u username -m password"
exit 1
#判斷第三個參數
if [ "$3" != "-m" ];then
#判斷參數個數
if [ $# -ne 4 ];then
echo " createuser.sh -u username -m password"
#判斷第二個參數
if [ $decide -ne 0 ];then
echo "使用者僅包含字母數字和下劃線"
else
if [ $id -eq 0 ];then
if [ "$mima" == "!!" -o "$mima" == "" ];then
`echo "$4" |passwd --stdin $2 &>/dev/null`
echo "$2密碼已更新"
`useradd $2`
`echo $4 |passwd --stdin $2 &>/dev/null`
echo "使用者$2已建立并更新密碼"
#删除變量
unset decide
unset id
unset mima
解析:先定義變量decide,id,mima,再對變量進行測試。
練習:
1.寫一個腳本名為jiaozuoyexx.sh 當執行該腳本時如jiaozuoyeXX.sh testXX.sh,就會自動将該testXX.sh傳給教師機,
路徑是scp testXX.sh [email protected]:~/scripts 密碼為mage26
1、vim jiaozuoye.sh
--------------------------
# Filename:
# Revision:
# Date:
# Author:
# Email:
# Website:
# Description:
# ------------------------------------------
scp $1 [email protected]:~/scripts
2、chmod +x createshXX.sh 添權重限
3、./jiaozuoyeXX.sh jiaozuoyeXX.sh 檢視結果
思路:這裡的$1實際是個參數,代表腳本名稱。
2.寫一個能夠建立新腳本的Shell script,如名為createshXX.sh 當執行時createsh /root/bin/test1.sh
則會自動建立并打開/root/bin/test1.sh,且其中包含以下内容。
1、vim createshXX.sh
2、#!/bin/bash
echo "#!/bin/bash
" >>$1
chmod +x createshXX.sh
vim $1
3、修改腳本要進入vim createshXX.sh
4、./jiaozuoyeXX.sh createshXX.sh
此處>>表示追加
3、編寫腳本/root/bin/sumid.sh,計算/etc/passwd檔案中的第10個使用者和第20使用者的ID之和
1、./createsh36.sh(相當于一個指令) /root/bin/sumid.sh 進入編輯界面
#--------------------------------------------------
# Filename:/root/bin/sumid.sh
# Version:1.0
# Date:'date "+%F %T"'
# Author:Lemon.
# Description:ID之和
echo "$[$(cat /etc/passwd|head -10|tail -1|cut -d: -f3)+$(cat /etc/passwd|head -20|tail -1|cut -d: -f3)]"
chmod +x /root/bin/sumid.sh
4、cd /root/bin/ 需要進入腳本目錄才能檢視結果
5、./sumid.sh 檢視檔案結果
或uid=10 uid=20
Uid1=`head -$1 /etc/passwd|tail -1|cut -d: -f3`
Uid2=`head -$2 /etc/passwd|tail -1|cut -d: -f3`
Sumid=$[Uid1+Uid2]
echo "Sumid is $Sumid"
unset Uid1 Uid2 Sumid
分析:分别表示出第10個使用者和第20個使用者
4、編寫腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和檔案
1、./createsh36.sh sumfile.sh
file1=`ls -A /etc|wc -l`
file2=`ls -A /var|wc -l`
file3=`ls -A /usr|wc -l`
let sum=$file1+$file2+$file3
echo "$sum"
unset file1 file2 file3 sum
chmod +x sumfile.sh
3、 ./sumspace.sh /etc /var /usr
注意:要想引用一串指令需要用` `和$( )引用。
5、編寫腳本/root/bin/checkdisk.sh,檢查磁盤分區空間和inode使用率,如果超過80%,就發廣播警告空間将滿
diskused_max=`df | grep "/dev/sd"|sort -nr -k5|head -1|tr -s ' ' %|cut -d% -f5`
inodeused_max=`df -i| grep "/dev/sd"|sort -nr -k5|head -1|tr -s ' ' %|cut -d% -f5`
[ "$diskused_max" -gt "80" ] && wall "空間即将滿"||echo "空間使用率不超過80%"
[ "$inodeused_max" -gt "80" ] && wall "inode即将滿"||echo "inode使用率不超過80%"
unset diskused_max inodeused_max
解釋:搜尋到磁盤分區中的分區/dev/sd,sort -nr -k5表示取第5列然後按數字從大到小排列,tr -s ' ' %将空格替換成%,再剪切,随後和80比較。
-----------------------答案2---------------------------------------------------
dev=`df|grep "/dev/sd"|egrep -o "[0-9]{1,3}%"|sort -n|tail -n 1|cut -d% -f1`
ino=`df -i|egrep -o "[0-9]{1,3}%" |sort -n|tail -n 1|cut -d% -f1`
[[ "$dev" -gt 80 ]] || [[ "$ino" -gt 80 ]] && echo $(wall 磁盤已滿)||echo 還有很多利用空
間呦
unset dev
unset ino
解釋:egrep -o 隻顯示被模式比對的字串,[0-9]{1,3}%表示在空間使用率這裡前面的字元比對至少1次,最多3次,随後剪切,排序。這裡的比較用或表示,隻要有一個滿了,另一個不用比較,就能發出警報。
本文轉自 優果馥思 51CTO部落格,原文連結:http://blog.51cto.com/youguofusi/1965690