Linux開發學習筆記(二)
Shell程式設計
1、簡單介紹
Shell 指令碼(shell script),是一種為 shell 編寫的指令碼程式。Shell 程式設計跟 java、php 程式設計一樣,只要有一個能編寫程式碼的文字編輯器和一個能解釋執行的指令碼直譯器就可以了。簡單地講,shell程式設計就是對一堆Linux命令的邏輯化處理。
在電腦科學中,Shell俗稱殼(用來區別於核),是指“提供使用者使用介面”的軟體(命令解析器)。它類似於DOS下的command。com和後來的cmd。exe。它接收使用者命令,然後呼叫相應的應用程式。
文字作業系統與外部最主要的介面就叫做shell。shell是作業系統最外面的一層。shell管理你與作業系統之間的互動:等待你輸入,向作業系統解釋你的輸入,並且處理各種各樣的作業系統的輸出結果。
同時它又是一種程式設計語言。作為命令語言,它互動式解釋和執行使用者輸入的命令或者自動地解釋和執行預先設定好的一連串的命令;作為程式設計語言,它定義了各種變數和引數,並提供了許多在高階語言中才具有的控制結構,包括迴圈和分支。
在排序演算法中,Shell是希爾排序的名稱。
Shell註釋:
以"#"開頭的行就是註釋,會被直譯器忽略。
sh裡沒有多行註釋,只能每一行加一個#號。
示例1
第一行表示選擇使用bash shell。在shell中,#符號表示註釋。但是shell的第一行比較特殊,一般都會以#!開始來告訴系統其後路徑所指定的程式即是解釋此指令碼檔案的 Shell 程式。在linux中,bash shell使用是最多的。
第二行的echo命令用於向視窗輸出文字。,在這裡就是輸出hello world。
Shell程式檔案在建立之後(如hello_world.sh,一般將shell儲存為xxx.sh看起來會直觀一些),要賦予此檔案的可執行許可權。
輸入命令:chmod +x hello_world.sh #使指令碼具有執行許可權
然後執行:./hello_world.sh #
執行時,檔案前面一定要加./,告訴系統就在當前目錄找,執行其他二進位制程式也一樣。因為直接寫檔名的話,linux系統回去PATH裡面的路徑找,通常當前目錄是沒有加到PATH裡面的。
示例2
#!/bin/bash
#自定義變數hello
hello="hello world"
#使用自定義變數
echo $hello
#使用環境變數
echo $PATH
#新增/home/hzj/bin到PATH環境變數
PATH=$PATH:/home/hzj/bin
#使用環境變數
echo $PATH
執行./test.sh
注意:定義變數不用$符號,使用變數要加$。定義變數的時候,“=”左右千萬不要有空格。
第二行在自定義變數時,使用了雙引號,在shell程式設計中,如果變數出現了空格或者引號,那麼也必須加引號,否則就可以省略。如果沒有單引號或雙引號,shell會把空格後的字串解釋為命令。這樣基本就會出錯。
第五行顯示當前PATH環境變數,該變數的值又一系列冒號分隔的目錄名組成。如:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games。當我們執行程式時,shell自動跟據PATH變數的值去搜索該程式。
第六行是新增/home/hzj/bin到PATH環境變數。
示例3
這個表示將pwd執行結果(當前所在目錄)賦值給path變數。
2、Shell變數
1、Bourne shell有如下四種變數
使用者自定義變數
位置變數,即命令列引數
預定義變數
環境變數
2、自定義變數
有以下幾點規則:
1)命名只能使用英文字母,數字和下劃線,首個字元不能以數字開頭。
2)中間不能有空格,可以使用下劃線(_)
3)不能使用標點符號
4)不能使用bash裡的關鍵字(可用help命令檢視保留關鍵字)。
5)變數名和等號之間不能有空格
3、位置變數,即命令列引數
$0 與鍵入的命令列一樣,包含指令碼檔名
$1, $2, ……,$9 分別包含第一個到第九個命令列引數
$# 包含命令列引數的個數
[email protected] 包含所有命令列引數: “$1, $2, ……,$9”會一個一個拆分解析
$? 包含前一個命令的退出狀態
$* 包含所有命令列引數: “$1, $2, ……,$9”所有包括在一起解析的
$$ 包含正在執行程序的ID號
4、環境變數
HOME : /etc/passwd檔案中列出的使用者主目錄
IFS: Internal Field Separator,預設為空格,tab及換行符
PATH: shell 搜尋路徑
PS1, PS2: 預設提示符($)及換行提示符( > )
TERM: 終端型別,常用的有vt100, ansi, vt200, xterm等
這類變數是linux已定義的,我們可以直接使用。
5、使用變數
使用變數很簡單。$符號加上變數名就可以了。
如:
第四行的變數名外面的花括號是可選的,加不加都行,加花括號是為了幫助直譯器識別變數的邊界推薦給所有變數加上花括號,這是個好的程式設計習慣。
6、只讀變數
使用 readonly 命令可以將變數定義為只讀變數,只讀變數的值不能被改變。
如:
執行之後會報錯:
7、刪除變數
使用unset命令可以刪除變數,變數被刪除後不能再次使用。
如:
執行之後沒有任何輸出。
注意: unset 命令不能刪除只讀變數
8、變數型別
執行shell時,會同時存在三種變數:
1) 區域性變數 區域性變數在指令碼或命令中定義,僅在當前shell例項中有效,其他shell啟動的程式不能訪問區域性變數。
2) 環境變數 所有的程式,包括shell啟動的程式,都能訪問環境變數,有些程式需要環境變數來保證其正常執行。必要的時候shell指令碼也可以定義環境變數。
3) shell變數 shell變數是由shell程式設定的特殊變數。shell變數中有一部分是環境變數,有一部分是區域性變數,這些變數保證了shell的正常執行
9、shell字串
字串是shell程式設計中最常用最有用的資料型別(除了數字和字串,也沒啥其它型別好用了),字串可以用單引號,也可以用雙引號,也可以不用引號。單雙引號的區別跟PHP類似。
1)單引號
規則:
單引號裡的任何字元都會原樣輸出,單引號字串中的變數是無效的;
單引號字串中不能出現單引號(對單引號使用轉義符後也不行)。
2)雙引號
執行結果:
優點:
雙引號裡可以有變數
雙引號裡可以出現轉義字元
3)拼接字串
執行結果:
4)獲取字串
執行結果:
5)提取子字串
從字串第三個字元開始擷取6個字元
執行結果:
6)查詢子字串
查詢字元“w”的位置
執行結果:
注意:指令碼中是反引號`,這個符號在tab鍵上面,並且要在英文模式下使用。
3、shell傳遞引數
在執行 Shell 指令碼時,可以向指令碼傳遞引數,指令碼內獲取引數的格式為:$n。.n 代表一個數字,1 為執行指令碼的第一個引數,2 為執行指令碼的第二個引數,以此類推……
示例:
test.sh檔案內容為
執行輸入:./test.sh 1 2
以上就是向指令碼傳遞了兩個引數並輸出,其中$0為執行的檔名。
還有其他的引數處理:
$0 與鍵入的命令列一樣,包含指令碼檔名
$1, $2, ……,$9 分別包含第一個到第九個命令列引數
$# 包含命令列引數的個數
[email protected] 包含所有命令列引數: “$1, $2, ……,$9”會一個一個拆分解析
$? 包含前一個命令的退出狀態
$* 包含所有命令列引數: “$1, $2, ……, $9”所有包括在一起解析的
$$ 包含正在執行程序的ID號
$*與 [email protected] 區別:
相同點:都是引用所有引數。
不同點:只有在雙引號中體現出來。假設在指令碼執行時寫了三個引數 1、2、3,,則 " * " 等價於 "1 2 3"(傳遞了一個引數),而 "@" 等價於 "1" "2" "3"(傳遞了三個引數)。
4、shell陣列
bash支援一維陣列(不支援多維陣列),初始化時不需要定義陣列大小(與 PHP 類似)。與C語言類似,陣列元素的下標由0開始編號。獲取陣列中的元素要利用下標,下標可以是整數或算術表示式,其值應大於或等於0。Shell 陣列用括號來表示,元素用空格符號分割開
1)定義陣列
在Shell中,用括號來表示陣列,陣列元素用"空格"符號分割開。
陣列名=(值1 值2 值3 … 值n)
如:array_name=(value0 value1 value2)
my_array=(A B "C" D)
也可以單獨定義陣列的各個分量:
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen
可以不使用連續的下標,而且下標的範圍沒有限制。
2)讀取陣列
${陣列名[下標]}
${array_name[index]}
如:value=${array_name[n]}
使用@或*符號可以獲取陣列中的所有元素
如:echo ${array_name[@]}
echo ${array_name[*]}
3)獲取陣列的長度
獲取陣列長度的方法與獲取字串長度的方法相同
# 取得陣列元素的個數
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得陣列單個元素的長度
lengthn=${#array_name[n]}
示例:
執行結果:
5、shell基本運算子
1、運算子種類:
算數運算子
關係運算符
布林運算子
字串運算子
檔案測試運算子
原生bash不支援簡單的數學運算,但是可以通過其他命令來實現,例如 awk 和 expr,expr 最常用。
expr 是一款表示式計算工具,使用它能完成表示式的求值操作。
如:
執行結果:
注意:
表示式和運算子之間要有空格,例如 1+2 是不對的,必須寫成1 + 2。
完整的表示式要被 ` ` 包含,注意這個字元不是常用的單引號,使用的是反引號 `,在 Esc 鍵下邊。
2、算術運算子
下表列出了常用的算術運算子,假定變數 a 為 10,變數 b 為 20:
運算子 |
說明 |
舉例 |
+ |
加法 |
`expr $a + $b` 結果為 30。 |
- |
減法 |
`expr $a - $b` 結果為 -10。 |
* |
乘法 |
`expr $a \* $b` 結果為 200。 |
/ |
除法 |
`expr $b / $a` 結果為 2。 |
% |
取餘 |
`expr $b % $a` 結果為 0。 |
= |
賦值 |
a=$b 將把變數 b 的值賦給 a。 |
== |
相等。用於比較兩個數字,相同則返回 true。 |
[ $a == $b ] 返回 false。 |
!= |
不相等。用於比較兩個數字,不相同則返回 true。 |
[ $a != $b ] 返回 true。 |
注意:
1、條件表示式要放在方括號之間,並且要有空格,例如: [$a==$b] 是錯誤的,必須寫成 [ $a == $b ]。
2、乘號(*)前邊必須加反斜槓(\)才能實現乘法運算
示例:
執行結果:
3、關係運算符
關係運算符只支援數字,不支援字串,除非字串的值是數字。
運算子 |
說明 |
舉例 |
-eq |
檢測兩個數是否相等,相等返回 true。 |
[ $a -eq $b ] 返回 false。 |
-ne |
檢測兩個數是否相等,不相等返回 true。 |
[ $a -ne $b ] 返回 true。 |
-gt |
檢測左邊的數是否大於右邊的,如果是,則返回 true。 |
[ $a -gt $b ] 返回 false。 |
-lt |
檢測左邊的數是否小於右邊的,如果是,則返回 true。 |
[ $a -lt $b ] 返回 true。 |
-ge |
檢測左邊的數是否大於等於右邊的,如果是,則返回 true。 |
[ $a -ge $b ] 返回 false。 |
-le |
檢測左邊的數是否小於等於右邊的,如果是,則返回 true。 |
[ $a -le $b ] 返回 true。 |
4、布林運算子
運算子 |
說明 |
舉例 |
! |
非運算,表示式為 true 則返回 false,否則返回 true。 |
[ ! false ] 返回 true。 |
-o |
或運算,有一個表示式為 true 則返回 true。 |
[ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a |
與運算,兩個表示式都為 true 才返回 true。 |
[ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
5、邏輯運算子
運算子 |
說明 |
舉例 |
&& |
邏輯的 AND |
[[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| |
邏輯的 OR |
[[ $a -lt 100 || $b -gt 100 ]] 返回 true |
6、字串運算子
運算子 |
說明 |
舉例 |
= |
檢測兩個字串是否相等,相等返回 true。 |
[ $a = $b ] 返回 false。 |
!= |
檢測兩個字串是否相等,不相等返回 true。 |
[ $a != $b ] 返回 true。 |
-z |
檢測字串長度是否為0,為0返回 true。 |
[ -z $a ] 返回 false。 |
-n |
檢測字串長度是否為0,不為0返回 true。 |
[ -n $a ] 返回 true。 |
str |
檢測字串是否為空,不為空返回 true。 |
[ $a ] 返回 true。 |
注意:將字串運算子“=”與算術運算子的“==”區分,“==”是用於比較兩個數字,“=”是用於比較兩個字串。
示例
執行結果
7、檔案測試運算子
操作符 |
說明 |
舉例 |
-b file |
檢測檔案是否是塊裝置檔案,如果是,則返回 true。 |
[ -b $file ] 返回 false。 |
-c file |
檢測檔案是否是字元裝置檔案,如果是,則返回 true。 |
[ -c $file ] 返回 false。 |
-d file |
檢測檔案是否是目錄,如果是,則返回 true。 |
[ -d $file ] 返回 false。 |
-f file |
檢測檔案是否是普通檔案(既不是目錄,也不是裝置檔案),如果是,則返回 true。 |
[ -f $file ] 返回 true。 |
-g file |
檢測檔案是否設定了 SGID 位,如果是,則返回 true。 |
[ -g $file ] 返回 false。 |
-k file |
檢測檔案是否設定了粘著位(Sticky Bit),如果是,則返回 true。 |
[ -k $file ] 返回 false。 |
-p file |
檢測檔案是否是有名管道,如果是,則返回 true。 |
[ -p $file ] 返回 false。 |
-u file |
檢測檔案是否設定了 SUID 位,如果是,則返回 true。 |
[ -u $file ] 返回 false。 |
-r file |
檢測檔案是否可讀,如果是,則返回 true。 |
[ -r $file ] 返回 true。 |
-w file |
檢測檔案是否可寫,如果是,則返回 true。 |
[ -w $file ] 返回 true。 |
-x file |
檢測檔案是否可執行,如果是,則返回 true。 |
[ -x $file ] 返回 true。 |
-s file |
檢測檔案是否為空(檔案大小是否大於0),不為空返回 true。 |
[ -s $file ] 返回 true。 |
-e file |
檢測檔案(包括目錄)是否存在,如果是,則返回 true。 |
[ -e $file ] 返回 true。 |
6、shell echo命令
Shell 的 echo 指令與 PHP 的 echo 指令類似,都是用於字串的輸出。
1。顯示普通字串
echo "It is a test"
這裡的雙引號完全可以省略,以下命令與上面例項效果一致:
echo It is a test
2。顯示轉義字元
echo "\"It is a test\""
執行結果:
"It is a test"
同樣,雙引號也可以省略
3。顯示變數
read 命令從標準輸入中讀取一行,並把輸入行的每個欄位的值指定給 shell 變數。如果執行read語句時標準輸入無資料,則程式在此停留等候,知道資料的到來或被終止執行
如:
#!/bin/sh
read name
echo "$name It is a test"
這裡的name 是接收標準輸入的變數
執行結果:
hahaha #標準輸入
hahaha It is a test #輸出
示例
執行結果:
4。顯示換行
echo -e "OK! \n" # -e 開啟轉義
echo "It it a test"
輸出結果:
OK!
It it a test
5。顯示不換行
#!/bin/sh
echo -e "OK! \c" # -e 開啟轉義 \c 表示不換行
echo "It is a test"
輸出結果:
OK! It is a test
6。顯示結果定向至檔案
echo "It is a test" > myfile
7。原樣輸出字串,不進行轉義或取變數(用單引號)
echo '$name\"'
輸出結果:
$name\"
上面的結果說明了“$”這個取變數符號失去了它的功能,只是把它當做一個字元直接輸出。
8。顯示命令執行結果
echo `date`
注意: 這裡使用的是反引號 `, 而不是單引號 '。
結果將顯示當前日期
2018年 03月 30日 星期五 18:42:11 CST
7、shell的printf命令
printf 命令模仿 C 程式庫(library)裡的 printf() 程式。
printf 由 POSIX 標準所定義,因此使用 printf 的指令碼比使用 echo 移植性好。
printf 使用引用文字或空格分隔的引數,外面可以在 printf 中使用格式化字串,還可以制定字串的寬度、左右對齊方式等。預設 printf 不會像 echo 自動新增換行符,我們可以手動新增 \n。
printf 命令的語法:
printf format-string [arguments…]
引數說明:
format-string: 為格式控制字串
arguments: 為引數列表。
示例
#!/bin/bash
printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 楊過 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
執行指令碼,輸出結果如下所示:
姓名 性別 體重kg
郭靖 男 66.12
楊過 男 48.65
郭芙 女 47.99
%s %c %d %f都是格式替代符
%-10s 指一個寬度為10個字元(-表示左對齊,沒有則表示右對齊),任何字元都會被顯示在10個字元寬的字元內,如果不足則自動以空格填充,超過也會將內容全部顯示出來。
%-4.2f 指格式化為小數,其中.2指保留2位小數。
%d %s %c %f 格式替代符詳解:
d: Decimal 十進位制整數 -- 對應位置引數必須是十進位制整數,否則報錯!
s: String 字串 -- 對應位置引數必須是字串或者字元型,否則報錯!
c: Char 字元 -- 對應位置引數必須是字串或者字元型,否則報錯!
f: Float 浮點 -- 對應位置引數必須是數字型,否則報錯
Printf的轉義序列
序列 |
說明 |
\a |
警告字元,通常為ASCII的BEL字元 |
\b |
後退 |
\c |
抑制(不顯示)輸出結果中任何結尾的換行字元(只在%b格式指示符控制下的引數字串中有效),而且,任何留在引數裡的字元、任何接下來的引數以及任何留在格式字串中的字元,都被忽略 |
\f |
換頁(formfeed) |
\n |
換行 |
\r |
回車(Carriage return) |
\t |
水平製表符 |
\v |
垂直製表符 |
\\ |
一個字面上的反斜槓字元 |
\ddd |
表示1到3位數八進位制值的字元。僅在格式字串中有效 |
\0ddd |
表示1到3位的八進位制值字元 |
8、shell的test命令
Shell中的 test 命令用於檢查某個條件是否成立,它可以進行數值、字元和檔案三個方面的測試。
每種測試物件都有若干測試操作符
例如:
test “$answer”= “yes”
變數answer的值是否為字串yes
test $num -eq 18
變數num的值是否為整數18
test –d tmp
測試tmp是否為一個目錄名
1、數值測試
引數 |
說明 |
-eq |
等於則為真 |
-ne |
不等於則為真 |