前言
什么是shell腳本呢?shell腳本就是利用shell的功能所寫的一個(gè)純文本的程序,將一些shell的語法和命令寫在里面,搭配正則表達(dá)式,管道命令,數(shù)據(jù)流重定向等功能,達(dá)到我們所想要的處理結(jié)果。
簡單的說,就是講很多命令寫在一起,讓用戶一下可以處理復(fù)雜的操作。(執(zhí)行一個(gè)shell script,就能夠一次執(zhí)行很多條命令)
變量
變量是shell腳本中的一個(gè)重要角色,當(dāng)然學(xué)習(xí)其他任何語言都會接觸到變量這個(gè)詞。shell腳本中的變量不需要聲明類型,直接只用變量名=變量值即可聲明一個(gè)變量。
- 變量的分類可以分為如下四種:
- 局部變量
定義在腳本內(nèi)的,只能在當(dāng)前腳本中使用。例如:name=longlongago
其中name是變量名,longlongago是變量的值,中間用=連接,=號的兩邊不能留空格。 - 環(huán)境變量
可以在任意一個(gè)腳本中使用的變量,稱為環(huán)境變量,例如常見的PATH。可以通過env命令查看當(dāng)前的環(huán)境變量:
[root@iZxvryruh5alhlZ ~]# env
XDG_SESSION_ID=215
HOSTNAME=iZxvryruh5alhlZ
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_TTY=/dev/pts/1
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/data/mysql/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin
PWD=/root
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env
那么如何聲明一個(gè)環(huán)境變量呢?很簡單,通過export既可以將一個(gè)局部變量聲明為環(huán)境變量,例如:
[root@iZxvryruh5alhlZ ~]# name=longlongago
[root@iZxvryruh5alhlZ ~]# export name
此時(shí)再次運(yùn)行env命令可以看到多了一個(gè)name變量。
- 參數(shù)變量
參數(shù)變量也稱位置變量,專門為了表示一個(gè)腳本傳遞的參數(shù)信息,如下:
#執(zhí)行一個(gè)腳本install.sh,具有三個(gè)參數(shù)faster、higher、stronger
sh install.sh faster higher stronger
#其中:
#$0:腳本本身的名字,即install
#$1:腳本傳入的第一個(gè)參數(shù),即faster
#$2:腳本傳入的第一個(gè)參數(shù),即higher
#$3:腳本傳入的第一個(gè)參數(shù),即stronger
- shell變量
就是每個(gè)shell腳本都具備的命令,用來表示一定的功能,具體看下表所示:
| 命令 | 含義 |
|---|---|
| $# | 傳遞給腳本的參數(shù)個(gè)數(shù) |
| $@ | 顯示所有參數(shù) |
| $* | 與$*相同 但每個(gè)參數(shù)都加上了引號' |
| $$ | 當(dāng)前進(jìn)程ID |
| $! | 后臺運(yùn)行的最后進(jìn)程ID |
| $. | 同set |
| $? | 顯示最后命令的退出狀態(tài),0表示沒有錯(cuò)誤 |
- 變量的使用
- 使用$符號跟變量名,如
echo $name - 雙引號和單引號的區(qū)別:
雙引號""中的內(nèi)容如果包含$變量名,那么會引用變量,例如:
name=longlongago
echo "my name is $name"
#輸出結(jié)果:my name is longlongago
單引號''中的內(nèi)容不會引用變量,是什么就顯示什么,例如:
name=longlongago
echo 'my name is $name'
#輸出結(jié)果:my name is $name
數(shù)據(jù)流重定向
什么是數(shù)據(jù)流重定向呢?比如說我們執(zhí)行一個(gè)命令,這個(gè)命令會讀取一個(gè)文件的數(shù)據(jù),然后再將數(shù)據(jù)顯示到屏幕上或者某個(gè)文件中。舉一個(gè)栗子:
#將根目錄下的目錄和文件夾輸出到/data/rootfile文件中
ll / > /data/rootfile
#標(biāo)準(zhǔn)輸出,使用 >或>>,>表示覆蓋,>>表示追加
#標(biāo)準(zhǔn)錯(cuò)誤輸出,使用 2>或2>>,2>表示覆蓋,2>>表示追加
如果要將錯(cuò)誤信息忽略掉而不顯示或存儲呢?這個(gè)時(shí)候黑洞設(shè)備/dev/null就很重要了,這個(gè)/dev/null可以吃掉任何導(dǎo)向它的消息被忽略。例如:
id ccc 2>/dev/null
#由于ccc用戶不存在,則命令運(yùn)行后會將錯(cuò)誤信息發(fā)到/dev/null設(shè)備,從而被忽略。
管道命令
如果有一群數(shù)據(jù)必須經(jīng)過多個(gè)步驟處理,最后形成我們需要的參數(shù)或者變量。管道命令使用的是"|",主要是將前一個(gè)命令的standout做為后一個(gè)standin來完成高難度操作。
栗子:
#查詢最后登陸的賬戶信息,并且用空格分隔,剪接出第一列賬戶名
last | cut -d ' ' -f 1
邏輯判斷
邏輯判斷命令有&&和||兩種,命令的具體說明我們來看一下如下的表格:
| 命令執(zhí)行情況 | 說明 |
|---|---|
| cmd1 && cmd2 | 若cmd1執(zhí)行完畢且正確($? = 0),則執(zhí)行cmd2; 若cmd1執(zhí)行完畢且為錯(cuò)誤($? != 0),則cmd2不執(zhí)行。 |
| cmd1 || cmd2 | 若cmd1執(zhí)行完畢且正確($? = 0),則cmd2不執(zhí)行; 若cmd1執(zhí)行完畢且為錯(cuò)誤($? != 0),則執(zhí)行cmd2。 |
舉個(gè)栗子:
#用戶組cxl不存在,則添加用戶組cxl
[ -z "$(grep 'cxl' /etc/group)" ] && groupadd cxl
#若用戶cxl不存在,則添加用戶cxl
id cxl || useradd cxl
條件判斷
1. if...then
語法:
if [ 條件判斷式 ];then
#這里寫:當(dāng)條件成立時(shí),需要執(zhí)行的命令
fi
語法還是比較簡單的,需要注意的是:方括號[]與中間的條件判斷式必須有一個(gè)空格。條件判斷式可以有很多種,包括了對整數(shù)的判斷、文件的判斷、字符串的判斷、多重條件判斷等。
- 數(shù)值判斷所用到的語法如下:
| 判斷標(biāo)志 | 代表含義 |
|---|---|
| -eq | 相等 |
| -ne | 不相等 |
| -gt | 大于 |
| -ge | 大于等于 |
| -lt | 小于 |
| -le | 小于等于 |
- 文件判斷的語法:
| 判斷標(biāo)志 | 代表含義 |
|---|---|
| -e | 該文件名是否存在 |
| -f | 該文件名是否存在,且是一個(gè)文件 |
| -d | 該文件名是否存在,且是一個(gè)目錄 |
| -r | 該文件名是否存在,且可讀 |
| -w | 該文件名是否存在,且可寫 |
| -x | 該文件名是否存在,且可執(zhí)行 |
*字符串的判斷
| 判斷標(biāo)志 | 代表含義 |
|---|---|
| -z | 字符串是否為空 |
| -n | 字符串是否為非空 |
| = | 字符串是否相等 |
| != | 字符串是否不相等 |
- 多重條件判斷
| 判斷標(biāo)志 | 代表含義 |
|---|---|
| -a | 兩個(gè)條件同時(shí)成立!即:并且 |
| -o | 兩個(gè)條件之一成立!即:或者 |
| ! | 反向狀態(tài) |
2.case...in...
語法:
case $變量名 in
"第一個(gè)變量內(nèi)容")
#成立時(shí),需要執(zhí)行的內(nèi)容
;;
"第二個(gè)變量內(nèi)容")
#成立時(shí),需要執(zhí)行的內(nèi)容
;;
*)#這里*表示除了第一和第二種的其他所有情況
exit 1
;;
esac
循環(huán)
1. while do done
語法:
while [ 條件判斷式 ]
do
#程序塊
done
表示當(dāng)條件成立時(shí)執(zhí)行do后面的內(nèi)容。
2. until do done
語法:
until [ 條件判斷式 ]
do
#程序塊
done
表示當(dāng)條件成立時(shí)停止執(zhí)行do后面的內(nèi)容。
3. for do done
語法:
for var in '一個(gè)數(shù)列'
do
#程序塊
done
遍歷數(shù)列中所有的元素,執(zhí)行程序塊中的內(nèi)容。
函數(shù)
function
shell的執(zhí)行順序是自上而下,從左往右,因此shell中的方法一定要放在前面。
- function的語法:
function fname() {
程序段
}
- function的使用:
function的使用,直接用函數(shù)的名字就可以了,但是如何傳遞參數(shù)呢?這其實(shí)跟shell腳本的參數(shù)變量一樣,$0表示當(dāng)前方法名,$1、$2、$3等表示當(dāng)前方法的第一、二、三個(gè)三處,如下
fname zhaoqian sunli zhouwu
其中fname表示函數(shù)名,zhaoqian、sunli、zhouwu分別代碼第一、二、三個(gè)參數(shù)。