目錄php
Markdown版本筆記 | 個人GitHub首頁 | 個人博客 | 個人微信 | 個人郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
Shell 是一個用 C 語言
編寫的程序,它是用戶使用 Linux
的橋樑。Shell 既是一種命令語言
,又是一種程序設計語言
。linux
Shell 是指一種應用程序
,這個應用程序提供了一個界面
,用戶經過這個界面訪問操做系統內核的服務
。git
Ken Thompson 的 sh
是第一種 Unix Shell,Windows Explorer
是一個典型的圖形界面 Shell
。github
Shell 腳本(shell script
),是一種爲 shell 編寫的腳本程序。shell
業界所說的 shell 一般都是指 shell 腳本,但讀者朋友要知道,shell
和 shell script
是兩個不一樣的概念。編程
因爲習慣的緣由,簡潔起見,本文出現的 shell編程
都是指 shell 腳本編程
,不是指開發 shell 自身。vim
Shell 編程跟 JavaScript、php 編程同樣,只要有一個能編寫代碼的文本編輯器
和一個能解釋執行
的腳本解釋器
就能夠了。數組
Linux 的 Shell 種類衆多,常見的有:bash
本教程關注的是 Bash
,也就是 Bourne Again Shell
,因爲易用和免費
,Bash 在平常工做中被普遍使用。同時,Bash 也是大多數Linux 系統默認的 Shell
。微信
在通常狀況下,人們並不區分 Bourne Shell
和 Bourne Again Shell
,因此,像 #!/bin/sh
,它一樣也能夠改成 #!/bin/bash
。
#!
用於告訴系統其後路徑所指定的程序便是解釋此腳本文件的 Shell 程序。
打開文本編輯器(可使用 vi/vim 命令來建立文件),新建一個文件 test.sh,擴展名爲 sh(sh表明shell),擴展名並不影響腳本執行
,見名知意就好,若是你用 php 寫 shell 腳本,擴展名就用 php 好了。
輸入一些代碼,第一行通常是這樣:
實例
#!/bin/bash # 使用哪種 Shell,能夠省略。不能在 #! 的行末添加註釋 echo "Hello World !" # 向窗口輸出文本
#!
是一個約定的標記,它告訴系統這個腳本須要什麼解釋器來執行,即便用哪種 Shell。這一行通常也是能夠省略的。echo
命令用於向窗口輸出文本。運行 Shell 腳本有兩種方法:
一、做爲可執行程序
將上面的代碼保存爲 test.sh
,並 cd
到相應目錄:
chmod +x ./test.sh #使腳本具備執行權限,能夠省略 ./test.sh #執行腳本
注意,必定要寫成 ./test.sh
,而不是 test.sh
,運行其它二進制的程序也同樣,直接寫 test.sh,linux 系統會去 PATH 裏尋找有沒有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin
等在 PATH 裏,你的當前目錄一般不在 PATH 裏,因此寫成 test.sh 是會找不到命令的,要用 ./test.sh
告訴系統說,就在當前目錄找
。
二、做爲解釋器參數
這種運行方式是,直接運行解釋器,其參數就是 shell 腳本的文件名,如:
/bin/sh test.sh # 一樣能夠按上面那種方式執行【/bin/sh ./test.sh】 /bin/php test.php
這種方式運行的腳本,不須要在第一行指定解釋器信息(寫了也沒用,由於會以運行時指定的解釋器爲準)。
定義變量時,變量名不加美圓符號$
,如:
your_name="runoob.com"
注意,變量名和等號之間不能有空格,這可能和你熟悉的全部編程語言都不同!
除了顯式地直接賦值,還能夠用語句給變量賦值,如:
for file in `ls /etc` #注意,這裏用的是反斜槓而不是單引號,表示的是執行結果 do printf "當前目錄的文件:" echo $file done
for file in `ls /etc`; do echo 當前目錄的文件:$file; done #注意,若是換行了能夠省略分號,不然不能省略
for file in $(ls /etc); do echo $file; done
以上語句將 /etc
下目錄的文件名循環出來。
使用一個定義過的變量,只要在變量名前面加美圓符號
便可,如:
your_name="qinjx" echo $your_name echo ${your_name}
變量名外面的花括號
是可選的,加不加都行,加花括號是爲了幫助解釋器識別變量的邊界
,好比下面這種狀況:
for skill in Ada Coffe Action Java; do echo "I am good at ${skill}Script" done
I am good at AdaScript I am good at CoffeScript I am good at ActionScript I am good at JavaScript
若是不給skill變量加花括號,寫成echo "I am good at $skillScript"
,解釋器就會把$skillScript
當成一個變量(其值爲空),代碼執行結果就不是咱們指望的樣子了。
推薦給全部變量加上花括號,這是個好的編程習慣。
已定義的變量,能夠被從新定義
,如:
your_name="tom" echo $your_name your_name="alibaba" echo $your_name
這樣寫是合法的,但注意,第二次賦值的時候不能加美圓符,使用變量的時候才加美圓符。
使用 readonly
命令能夠將變量定義爲只讀變量,只讀變量的值不能被改變
。
readonly myUrl="http://www.google.com"
myUrl="http://www.google.com" readonly myUrl
下面的例子嘗試更改只讀變量,結果報錯:
readonly myUrl="http://www.google.com" myUrl="http://www.runoob.com" #報錯 ./test.sh: line 2: myUrl: readonly variable
使用 unset
命令能夠刪除變量。語法:
unset variable_name
變量被刪除後不能再次使用
。unset 命令不能刪除只讀變量
。
myUrl="http://www.runoob.com" unset myUrl echo $myUrl #不報錯,但沒有任何輸出
readonly myUrl="http://www.runoob.com" unset myUrl #報錯./test.sh: line 2: unset: myUrl: cannot unset: readonly variable
字符串是shell編程中最經常使用最有用的數據類型(除了數字和字符串
,也沒啥其它類型好用了),字符串能夠用單引號
,也能夠用雙引號
,也能夠不用引號
。單雙引號的區別跟PHP相似。
str='this is a string'
單引號字符串的限制:
不能出現單獨一個的單引號
,對單引號使用轉義符後也不行()name=白乾濤 test1='hello, ${name}sir!' #不加符號,原樣輸出,hello, ${name}sir! test2='hello, `$name`sir!' #加反斜槓,原樣輸出,hello, `$name`sir! test3='hello, "$name"sir!' #加雙引號,原樣輸出,hello, "$name"sir! test4='hello, '$name'sir!' #加單引號,正常輸出,hello, 白乾濤sir! echo $test1 $test2 $test3 $test4
雙引號裏能夠有變量,能夠出現轉義字符
name=白乾濤 test1="hello, ${name}sir!" #不加符號,hello, 白乾濤sir! test2="hello, \`$name\`sir!" #加反斜槓且轉義,hello, `白乾濤`sir! test3="hello, "$name"sir!" #加雙引號,hello, 白乾濤sir! test4="hello, \"$name\"sir!" #加雙引號且轉義,hello, "白乾濤"sir! test5="hello, '$name'sir!" #加單引號,hello, '白乾濤'sir! test6="hello, \'$name\'sir!" #加單引號且轉義,hello, \'白乾濤\'sir! echo $test1 $test2 $test3 $test4 $test5 $test6 echo "hello, `$name`sir!" #反斜槓必須轉義,不然報錯./test.sh: line 10: 白乾濤: command not found
string="baiqiantao" echo "字符串長度:${#string}" #字符串長度:4 echo "子串爲:${string:3:4}" #從第 index 個字符開始截取 length 個字符。子串爲:qian echo "字符位置:`expr index "$string" qt`" # 字符位置:4(index+1) # 查找字符 q 或 t 的位置(哪一個字母先出現就計算哪一個),以上是反引號 `,而不是單引號 '
bash支持一維數組(不支持多維數組
),而且沒有限定數組的大小
。
相似於 C 語言,數組元素的下標由 0
開始編號。獲取數組中的元素要利用下標,下標能夠是整數或算術表達式
,其值應大於或等於 0。
在 Shell 中,用小括號
來表示數組,數組元素用空格或換行
符號分割開,初始化時不須要定義數組大小。
定義數組的通常形式爲:
數組名=(值1 值2 ... 值n)
array=(A 2 "C" 4.3 '5')
還能夠單獨定義數組的各個份量,能夠不使用連續的下標,並且下標的範圍沒有限制:
array[1]=1 array[5]=5 array[n]=白乾濤 #這裏的n表明某一個整數,若是未定義直接使用,表明0
基本操做
${array_name[*]}
或${array_name[@]}
${array_name[index]}
,index是從0開始的${#array_name[*]}
或${#array_name[@]}
${#array_name[index]}
array=(A 2 "C" 4.3 '5') array[8]=8 array[n]=白乾濤 #這裏的n表明某一個整數,若是未定義直接使用,表明0 echo "數組的元素爲: ${array[*]}" #白乾濤 2 C 4.3 5 8 echo "第一個元素爲: ${array[0]}" #白乾濤 echo "數組的長度爲:${#array[*]}" #6 echo "第一個元素長度爲: ${#array[0]}" #3
以 #
開頭的行
就是註釋,會被解釋器忽略。
若是在開發過程當中,遇到大段的代碼須要臨時註釋起來,過一下子又取消註釋,能夠把這一段要註釋的代碼用一對花括號
括起來,定義成一個函數
,沒有地方調用這個函數,這塊代碼就不會執行,達到了和註釋同樣的效果。
多行註釋還可使用如下格式:
:<<EOF 註釋內容... EOF
EOF 也可使用其餘符號。
咱們能夠在執行 Shell 腳本時,向腳本傳遞參數,腳本內獲取參數的格式爲:$n
,n 表明第 n 個參數
echo "你的性別:$2"; echo "你的年齡:$1";
執行腳本:
./test.sh 29 男 你的性別:男 你的年齡:29
有幾個特殊字符用來處理參數:
符號 | 說明 |
---|---|
$0 |
執行的文件名 |
$# |
傳遞到腳本的參數個數 |
$* |
以一個單字符串顯示全部 向腳本傳遞的參數 |
$@ |
與$* 相同,可是使用時加引號,並在引號中返回每一個參數 |
$$ |
腳本運行的當前進程ID號 |
$! |
後臺運行的最後一個進程的ID號 |
$- |
顯示Shell使用的當前選項,與set 命令功能相同。 |
$? |
顯示最後命令的退出狀態。0表示沒有錯誤,其餘任何值代表有錯誤。 |
echo "你的年齡:$1"; echo -e "你的性別:$2\n"; echo "執行的文件名:$0"; echo -e "參數個數爲:$#\n"; echo "傳遞的參數做爲一個字符串顯示:$*"; echo -e "傳遞的參數做爲一個字符串顯示:$@\n"; echo "腳本運行的當前進程ID號:$$"; echo "後臺運行的最後一個進程的ID號 :$!"; echo "顯示Shell使用的當前選項:$-"; echo "顯示最後命令的退出狀態:$?";
執行腳本,輸出結果以下所示:
./test.sh 29 男 你的年齡:29 你的性別:男 執行的文件名:./test.sh 參數個數爲:2 傳遞的參數做爲一個字符串顯示:29 男 傳遞的參數做爲一個字符串顯示:29 男 腳本運行的當前進程ID號:14372 後臺運行的最後一個進程的ID號 : 顯示Shell使用的當前選項:hB 顯示最後命令的退出狀態:0
$*
與 $@
的異同點雙引號
中體現出來,假設在腳本運行時寫了三個參數 一、二、3
:
" * "
等價於 "1 2 3"
(傳遞了一個參數)"@"
等價於 "1"
"2"
"3"
(傳遞了三個參數)。相同點:都是引用全部參數
for i in $*; do # 【$*】、【$@】、【"$@"】的結果是同樣的 echo $i done
./test.sh 29 男 白乾濤 29 男 白乾濤
不一樣點:在雙引號中,"$*"
的做用是將全部參數當作一個參數
for i in "$*"; do echo $i done
./test.sh 29 男 白乾濤 29 男 白乾濤
Shell 和其餘編程語言同樣,支持多種運算符,包括:
原生bash不支持簡單的數學運算
,可是能夠經過其餘命令來實現,例如 awk
和 expr
。expr 是一款表達式計算工具
,使用它能完成表達式的求值
操做。
val=`expr 2 + 2` echo "兩數之和爲 : $val" #兩數之和爲 : 4
兩點注意:
2+2
是不對的,必須寫成 2 + 2
,這與咱們熟悉的大多數編程語言不同反引號
包含,注意這個字符不是經常使用的單引號
下表列出了經常使用的算術運算符,假定變量 a 爲 10,變量 b 爲 20:
運算符 | 說明 |
---|---|
+ | 加法 |
- | 減法 |
* | 乘法 |
/ | 除法 |
% | 取餘 |
= | 賦值 |
== | 相等 |
!= | 不相等 |
注意:
*
前邊必須加反斜槓\
才能實現乘法運算$((表達式))
,此處表達式中的 *
不須要轉義符號\
關係運算符只支持數字
,不支持字符串,除非字符串的值是數字。
下表列出了經常使用的關係運算符,假定變量 a 爲 10,變量 b 爲 20:
運算符 | 說明 |
---|---|
-eq | 檢測兩個數是否相等 |
-ne | 檢測兩個數是否不相等 |
-gt | 檢測左邊的數是否大於 右邊的 |
-lt | 檢測左邊的數是否小於 右邊的 |
-ge | 檢測左邊的數是否大於等於 右邊的 |
-le | 檢測左邊的數是否小於等於 右邊的 |
下表列出了經常使用的布爾運算符,假定變量 a 爲 10,變量 b 爲 20:
運算符 | 說明 |
---|---|
! | 非運算 |
-o | 或運算,or |
-a | 與運算,and |
如下介紹 Shell 的邏輯運算符,假定變量 a 爲 10,變量 b 爲 20:
&&
邏輯與 [[ $a -lt 100 && $b -gt 100 ]]
返回 false||
邏輯或 [[ $a -lt 100 || $b -gt 100 ]]
返回 true下表列出了經常使用的字符串運算符,假定變量 a 爲 "abc",變量 b 爲 "efg":
運算符 | 說明 |
---|---|
= | 檢測兩個字符串是否相等 |
!= | 檢測兩個字符串是否不相等 |
-z | 檢測字符串長度是否爲0 |
-n | 檢測字符串長度是否不爲0 |
$ | 檢測字符串是否不爲空 |
文件測試運算符用於檢測 Unix 文件的各類屬性。
操做符 | 說明 |
---|---|
-b file | 檢測文件是否是塊設備文件 |
-c file | 檢測文件是否是字符設備文件 |
-d file | 檢測文件是否是目錄 |
-f file | 檢測文件是否是普通文件 既不是目錄,也不是設備文件 |
-g file | 檢測文件是否設置了 SGID 位 |
-k file | 檢測文件是否設置了粘着位 (Sticky Bit) |
-p file | 檢測文件是否是有名管道 |
-u file | 檢測文件是否設置了 SUID 位 |
-r file | 檢測文件是否可讀 |
-w file | 檢測文件是否可寫 |
-x file | 檢測文件是否可執行 |
-s file | 檢測文件是否爲空 (文件大小是否大於0) |
-e file | 檢測文件(包括目錄)是否存在 |
其餘檢查符:
Shell 的 echo 指令與 PHP 的 echo 指令相似,都是用於字符串的輸出。
echo 會自動添加換行符。
echo "It is a test" #顯示普通字符串,每輸出一次會自動換行 echo It is a test #雙引號徹底能夠省略 echo "\"It is a test\"" #顯示轉義字符【"It is a test"】,雙引號一樣也能夠省略 name=白乾濤 echo "$name It is a test" #顯示變量,雙引號一樣也能夠省略 echo -e "It is a test\n" #顯示換行,【-e】爲開啓轉義,【\n】表示換行 echo -e "It is a test\c" #顯示不換行,【\c】表示不換行,【\c】後面的內容會丟棄 echo '---$name\"' #用單引號能夠原樣輸出字符串,不進行轉義或取變量 echo `date` #使用反引號能夠顯示命令執行的結果
It is a test It is a test "It is a test" 白乾濤 It is a test It is a test It is a test---$name\" 2019年11月 4日 0:05:17
printf 命令模仿 C 程序庫裏的 printf() 程序。
printf 由 POSIX 標準所定義,所以使用 printf 的腳本比使用 echo 移植性好
。
printf 使用引用文本或空格分隔的參數,外面能夠在 printf 中使用格式化字符串,還能夠制定字符串的寬度、左右對齊方式等。
默認 printf 不會像 echo 自動添加換行符,咱們能夠手動添加 \n。
printf 命令的語法:
printf format-string [arguments...] #格式控制字符串 爲參數列表
%s
、%c
、%d
、%f
都是格式替代符
,分別表明替換字符串、字符、整數、浮點數,例如:
printf "%-9s %-6s %5s\n" 姓名 性別 體重kg printf "%-9s %-3s %5.2f\n" 白乾濤 男 66.1 printf "%-9s %-3s %5.2f\n" 白乾濤 M 66.1 printf "%-9s %-3s %5.2f\n" 乾濤 男 6.1 printf "%-9s %-3s %5.2f\n" baiqiantao 男 666.1234
姓名 性別 體重kg #空格數四、1 白乾濤 男 66.10 #空格數一、1 白乾濤 M 66.10 #空格數一、3 乾濤 男 6.10 #空格數四、2 qiantao 男 666.12 #空格數三、1
其中:
%-9s
指寬度爲9個字符
(一箇中文算3個字符、一個英文算一個字符),若是寬度不足則自動以空格填充
,超過也會將內容所有顯示出來
。其實能夠理解爲最少顯示n個字符。-
表示左對齊
,沒有則表示右對齊。%-5.2f
指格式化爲小數,其中5表明(最少)顯示幾個字符(小數點也算在內),.2
指(強制)保留2位小數。基本案例
printf "年齡:30\n" #能夠省略參數列表(此時即便有參數列表也是無效的)【年齡:30】 printf "年齡:%d\n" 30 #雙引號【年齡:30】 printf '年齡:%d\n' 30 #單引號,與雙引號效果同樣 printf 年齡:%d 30 # 沒有引號也能夠輸出
錯誤案例
printf %s "包青天\n" #【換行失敗】有格式化字符時,參數列表中的換行符無效 printf %s\n "白乾濤" #【換行失敗】格式化字符中有換行符時,須要用雙引號引住 # 打印內容【包青天\n白乾濤n】
格式只指定了一個參數,但多出的參數仍然會按照該格式輸出,format-string 被重用
printf 姓名:%s 白乾濤 包青天 #【姓名:白乾濤姓名:包青天】 printf "姓名:%s\n" 白乾濤 包青天 #【姓名:白乾濤(換行)姓名:包青天】 printf "%s %s %s\n" a b c d e f g #每3個一個換行
姓名:白乾濤姓名:包青天姓名:白乾濤 姓名:包青天 a b c d e f g
若是沒有 arguments,那麼 %s 用NULL代替,%d 用 0 代替,%c 用空格代替,%f 用 0.000000 代替
printf "%s和 %d 和%c和 %f \n" #【和 0 和 和 0.000000】
序列 | 說明 |
---|---|
\a |
警告字符,一般爲ASCII的BEL字符 |
\b |
後退 |
\c |
抑制(不顯示)輸出結果中任何結尾的換行字符(只在%b格式指示符控制下的參數字符串中有效),並且,任何留在參數裏的字符、任何接下來的參數以及任何留在格式字符串中的字符,都被忽略 |
\f |
換頁(formfeed) |
\n |
換行 |
\r |
回車(Carriage return) |
\t |
水平製表符 |
\v |
垂直製表符 |
\\ |
一個字面上的反斜槓字符 |
\ddd |
表示1到3位數八進制值的字符。僅在格式字符串中有效 |
\0ddd |
表示1到3位的八進制值字符 |
printf "%s\n" "白乾濤\n包青天" #【白乾濤\n包青天】 printf "%b\n" "白乾濤\n包青天" #【白乾濤(換行)包青天】
2019-9-1