Shell的做用是解釋執行用戶的命令,用戶輸入一條命令,Shell就解釋執行一條,這種方式稱爲交互式(Interactive),Shell還有一種執行命令的方式稱爲批處理(Batch),用戶事先寫一個Shell腳本(Script),其中有不少條命令,讓Shell一次把這些命令執行完,而沒必要一條一條地敲命令。Shell腳本和編程語言很類似,也有變量和流程控制語句,但Shell腳本是解釋執行的,不須要編譯,Shell程序從腳本中一行一行讀取並執行這些命令,至關於一個用戶把腳本中的命令一行一行敲到Shell提示符下執行。shell
用戶在命令行輸入命令後, 通常狀況下Shell 回fork一個子進程並exec該命令, 可是shell的內建命令例外, 執行內建命令至關與調用shell進程中的一個函數, 並不會建立新的進程, 例如:cd、alias、umask、exit 等命令都是內建命令, 凡是用which 命令查不到程序文件所在位置的命令都是內建命令, 內建命令沒有單獨的man手冊, 要在man手冊中查看內建命令, 應該用編程
# 查看內建的命令 $ man bash-builtins
寫一個簡單的shell腳本, t1.shbash
#!/bin/sh cd .. ls
說明:編程語言
shell 腳本中用# 表示註釋, 至關於C語言的//註釋, 但若是#位於第一行開頭, 而且是 #!(稱爲Shenbang)則例外, 它表示該腳本使用後面指定的解釋器/bin/sh解釋執行。 若是把這個腳本文件加上課執行權限而後執行函數
chmod a+x t1.sh # 經過 ./ 執行shell腳本 ./t1.sh
說明:ui
Shell 會fork一個子進程並調用exec執行 ./t1.sh這個程序, exec系統調應該把子進程的代碼段替換成 ./t1.sh 程序的代碼段, 並從它的 _start 開始執行, 然而 t1.sh 是個文本文件, 根本沒有代碼段和 _start 函數, 那怎麼辦??命令行
其實exec 還有另外以一種機制, 若是要執行的是一個文本文件, 而且第一行用Shebang指定的解釋器, 則用解釋器程序的代碼段替換當前進程, 而且從解釋器的 _start 開始執行, 而這個文本文件被看成命令參數傳給解釋器, 所以, 執行上述腳本至關於執行程序。code
執行shell 腳本的方式:進程
# 經過source 命令執行.sh文件 $ source t1.sh # 若是給文件添加了可執行權限, 能夠經過一下方式執行shell 腳本 $ chmod a+x t1.sh # 給該文件添加可執行權限 # 經過./執行腳本 $ ./t1.sh #直接用解釋器去執行該文件 $ /bin/sh ./t1.sh
若是將命令行下輸入的命令用()括起來, 這樣也會fork 一個子Shell 執行 ()括號中的命令, 一行能夠輸入由分號 ;隔開多條命令。ip
[czk@localhost ~]$ (cd ..;ls -l) total 0 drwx------. 2 czk czk 98 May 18 22:50 czk
若是沒有用括號將命令括起來, 則是在當前的shell進程進行執行, 並不會fork一個子進程進行去執行該命令。
變量的類型
本地變量
只存在於當前Shell進程, 用set命令能夠顯示當前shell進程中定義的全部變量, 包括本地變量、環境變量和函數。
# 定義本地變量, 等號 = 兩邊不能由空格,變量名通常用大寫+下劃線組成 [czk@localhost ~]$ VARNAME=czk
環境變量
環境變量能夠從父進程傳給子進程, 所以Shell進程的環境變量能夠從當前shell進程傳給fork出來的子進程。用printenv命令能夠顯示當前Shell進程的環境變量。
# 使用export 命令能夠將本地變量導出爲環境變量 [czk@localhost ~]$ export VARNAME=czk # 使用 unset 命令能夠刪除本地或環境變量 [czk@localhost ~]$ unset VARNAME [czk@localhost ~]$ echo ${VARNAME} # 空。。。。
變量能夠經過 $ 或者 ${varname} 進行取值
注意,在定義變量時不用$,取變量值時要用$。和C語言不一樣的是,Shell變量不須要明肯定義類型,事實上Shell變量的值都是字符串,好比咱們定義VAR=45,其實VAR的值是字符串45而非整數。Shell變量不須要先定義後使用,若是對一個沒有定義的變量取值,則值爲空字符串。
` 或者 $()
由 反引號 括起來的也是一條命令, Shell 先執行該命令, 而後將輸出結果馬上代換到當前命令行中。以下:
# date 日期函數 [czk@localhost ~]$ DATE=`date` [czk@localhost ~]$ echo $DATE Sat May 18 23:45:47 EDT 2019 # $() 方式 [czk@localhost ~]$ DATE=$(date) [czk@localhost ~]$ echo $DATE Sat May 18 23:47:20 EDT 2019
主要是用通配符就將文件匹配替換
* :匹配0個或者多個任意字符 ?:匹配一個任意字符 [若干字符] : 匹配方括號中任意一個字符的一次出現
$(())
這個是用來進行算術運算, $(()) 中的shell 變量取值將轉換成整數, 以下:
# $(())中只能用+-*/和()運算符,而且只能作整數運算。 [czk@localhost ~]$ NUM=99 [czk@localhost ~]$ echo $(($NUM+1)) 100
\ 在shell中被用做轉義字符用於去除緊跟其後的單個字符的特殊意義,
好比建立一個"$ $" 的文件
[czk@localhost ~]$ touch \$\ \$ [czk@localhost ~]$ ls $ $ test.sh
還有一個字符也比較特殊, 它沒有說明特殊含義, 可是用來作文件名也是比較麻煩的, 那就是 - 號。
它會把和它連在一塊兒的字符, 當成了命令行參數的命令選項了,若是你硬要用 它來做文件名, 能夠有以下兩種方式:
[czk@localhost ~]$ touch ./-hi [czk@localhost ~]$ ls $ $ -hi test.sh
OR
[czk@localhost ~]$ touch -- -hello [czk@localhost ~]$ ls $ $ -hello -hi test.sh
Shell 腳本中的單引號和雙引號同樣都是字符串的界定符,而不是字符的界定符, 單引號用於保存引號內全部字符的字面值, 即便引號內的\和回車也不例外,可是字符串中不能出現單引號。若是引號沒有配對就輸入回車,Shell會給出續行提示符,要求用戶把引號配上對。
[czk@localhost ~]$ echo '$SHELL' $SHELL
被雙引號用括住的內容,將被視爲單一字串。它防止通配符擴展,但容許變量擴展。這點與單引號的處理方式不一樣。
[czk@localhost ~]$ DATE=$(date) # 若是是雙引號, 還會繼續展開裏面的內容 [czk@localhost ~]$ echo "$DATE" Sun May 19 02:31:05 EDT 2019 [czk@localhost ~]$ echo '$DATE' $DATE