shell其實是相對於系統內核而言的,其是內核外層的一層“殼”,作用在於提供一個用戶圖形界面讓使用者可以通過一些命令和操作系統進行交互,從而完成一些動作。linux shell自然就是Linux系統的那一層“殼”,同樣的還有windows shell。因爲在shell上和os進行交互操作,需要輸入特定的命令,shell語言就是這些命令的集合以及一些額外的語法抽象層。筆者作爲一個linux shell的小白,本文將記錄一下關於linux shell的基於概念和語法,作爲一次簡單的linux shell入門。
本文中的shell將特指可以在圖形界面內訪問內核服務的一種命令集合,所以linux系統下具有多種不同的shell,即多種不同的命令集可以和linux系統的內核服務進行交互,常見的有以下幾種:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
本文將只針對Bourne Again Shell,也就是bash。
目錄
數據類型
shell語言裏面的基本數據類型有整數、布爾變量(true和fasle),字符串和數組,下面主要講一下字符串和數組。
字符串:可以使用單引號,或者雙引號,甚至不適用引號。區別在於,當使用單引號時,該字符串中不可出現變量和轉義,即使出現也會被認爲字面意思,即不會進行特殊處理;但是對於雙引號字符串,可以通過${var}的形式來引用變量var,同時也可以出現換行\n等轉義字符。無論是單引還是雙引,都可以通過連續多個字符串進行拼接,字符串之間無需任何連接標誌符。
數組:shell中數組的定義和python中的元組類似,都是使用圓括號,但是shell中圓括號的值使用空格符分隔,而python中則使用逗號分隔。shell中的元組還可以直接使用變量下標的方式定義,並且下標可以任意指定,如下所示。
#通過圓括號定義
arrayname=(1 2 3)
#直接通過變量和下標定義
arrname[0]=1
arrname[2]=3
賦值和變量引用
shell中使用等號=賦值,但是要注意的是,等號兩側的變量和值之間不能有空格。對此,可以這樣去記憶,對於shell中的語句,=或者其他符合兩側不能有空格,但是對於表達式,=或者其他運算符之間需要有空格隔開。
如果定義了一個變量,在後面如果要引用改變量,則需要通過${var}的形式來對變量var進行引用。
var=2
echo "the value of var is ${var}"
#output: the value of var is 2
獲取變量長度
當我們想要獲取一個變量的長度時,可以使用${#var}。要注意的是,對於#,其也是單行註釋符,並且在一行的最開始位置使用以引出註釋。
var="abc"
echo "the length of var is ${#var}"
#output: the length of var is 3
腳本的執行
對於bash腳本的執行有兩種主要的方式,第一種是直接在linux命令使用bash命令,即bash script.sh,這樣可以直接執行腳本;第二種方式可以不顯示使用bash命令,但是需要在腳本內部的首行告訴系統使用哪個解釋器來執行該腳本,具體方式是在腳本首行輸入#!/bin/bash,然後再在命令行通過chmod +x script.sh將腳本賦予可執行權限,然後輸入該腳本回車即可,這樣linux系統就可以通過第一行知道使用bash解釋器來執行該腳本了,這有點類似於python2在首行聲明指定腳本編碼。第二種方式要注意的是,在輸入腳本回車時,腳本使用的路徑需要完整,系統並不會默認現在當前目錄下尋找該腳本,而是會在環境變量中去尋找,如果沒有輸入完整路徑的話。
var="abc"
echo "the length of var is ${#var}"
#假設一個shell腳本只有上述語句,名爲script.sh,那麼在linux命令中要執行該腳本可使用以下兩種方式
#方式一:
$ bash srcipt.sh
$ the length of var is 3
#方式二,注意當前工作目錄是腳本所在目錄,所以使用.表示當前目錄以完整腳本目錄
$ chmod +x script.sh
$ ./script.sh
$ the length of var is 3
腳本參數傳遞以及參數獲取
在執行shell腳本時,可以直接在腳本後面以空格分隔參數,以將參數傳給腳本。在腳本內部,可以通過$n的方式獲取命令行中傳給腳本的第n個參數,其中第0個參數,即$0指的腳本名。要注意的是,當n>=10時,需要用${n}的方式獲取參數。同時,還可以通過$#來獲取除了腳本自身外的參數的個數;$*來一次性獲取除腳本外的所有參數,並以單個字符串的形式返回;$@也是獲取所有參數,但是是以多個字符串的形式返回,其中一個參數對應一個字符串。
變量
shell語言的變量可以分爲腳本自定義變量和預定義變量,自定義變量由字母、數字和下劃線組成,並且不能以數字開頭。可以通過readonly關鍵字將變量聲明爲只讀,這樣後面便無法更改該變量;通過unset var可以刪除var變量,將其設爲空值。
表達式
shell中,可以將表達式分爲一般表達式和條件測試表達式。所謂表達式是和語句相對應的,表達式是有結果返回的,而語句只是一個動作,比如賦值語句,沒有結果返回。對於一般表達式,比如使用`expr expression`,即通過expr來聲明;而條件測試表達式通過[]方括號聲明,方括號中的表達式返回bool變量,往往用在if條件測試中,同test。shell中表達式相比於語句的一個特點就是表達式的操作符和變量之間都有空格分隔,而語句則沒有分隔。
流程控制
shell中的流動控制有if條件語句,for循環,while循環,until語句,case語句,其格式分別如下所示。各個循環都支持break和continue。
#if語句
if condition;
then
action
fi
#if else語句
if condition1
then
action1
elif condition2
then
action1
else
action3
fi
#for循環
for v in v1 v2 v2 ...
do
actions
done
#while循環
while condition
do
actions
done
#while死循環
while true
do
actions
done
#或者
while :
do
actions
done
#untile循環
until condition
do
actions
done
shell函數
shell語言中,可以通過如下方式定義函數。其中[]的內容表示是可選的,寫不寫都不影響函數的構造。
[function] func[()]
{
actions;
[return int;]
}
#[]內容表示可選,所以最簡單的一個函數形式爲
func
{
action;
}
對於函數,要注意的是對於函數值的返回以及對函數參數的捕獲。首先對於函數的返回,通過緊接着在函數調用語句的下一條語句寫入$?來捕獲函數返回值,如果函數沒有return,則返回最後一條語句的結果被捕獲,並且還將返回一個函數是否正常結束的標誌,正常結束返回0,拋出錯誤返回1,這個0或1標誌不會被捕獲;對於函數參數,和腳本傳參一致,只是函數參數是在調用函數的時候緊接着傳入,而腳本傳參則是在命令行緊接着傳入。
IO重定向
expression > file:將expression的結果寫入file,並覆蓋file原有的內容;
expression >> file:將expression的結果寫入file,但是在file原有的內容的基礎上追加;
var < file:從file中獲取內容。
此外,可以通過腳本中read var中的read關鍵詞,從標準輸入流中輸入內容,即從命令行中輸入內容,並通過定義變量var捕獲。
導入外部文件
shell語言可以類比python,導入其他的外部腳本模塊,並且直接在腳本中引用被導入的腳本文件中的變量。具體的方式有兩種,第一種是通過. script.sh的形式,注意點號;第二種是通過source script.sh。如下所示。
#假設script1.sh如下
var1="test"
#script2.sh內容如下
. ./script1.sh
#或者
#source ./script1.sh
echo "the value of script1 is ${var1}"
#執行script2.sh腳本,輸入的內容爲:
$ the value of script1 is test
參考
Shell 教程 | 菜鳥教程:https://www.runoob.com/linux/linux-shell.html