天天看點

shell掃盲

一、shell概述

  1、shell與shell腳本

    1)shell

  shell是一個用C語言編寫的程式,它是使用者使用Linux的橋梁。shell既是一種指令行語言,又是程式設計語言。

  shell是指一種應用程式,這個應用程式提供了一個界面,使用者通過這個界面通路作業系統核心的服務。

  Ken Thompson 的 sh 是第一種 Unix Shell,Windows Explorer 是一個典型的圖形界面 Shell。

    2)shell腳本

  Shell 腳本(shell script),是一種為 shell 編寫的腳本程式。

  2、shell環境

  Shell 程式設計跟 JavaScript、php 程式設計一樣,要有一個能編寫代碼的文本編輯器和一個能解釋執行的腳本解釋器。

  • 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)
  • ........

  Bash也就是 Bourne Again Shell,由于易用和免費,Bash 在日常工作中被廣泛使用。同時,Bash 也是大多數Linux 系統預設的 Shell。

  在一般情況下,人們并不區分 Bourne Shell 和 Bourne Again Shell,是以,像 #!/bin/sh,它同樣也可以改為 #!/bin/bash。

  #! 告訴系統其後路徑所指定的程式即是解釋此腳本檔案的 Shell 程式。

二、shell變量

  1、定義變量

  變量名的命名規範

  • 命名隻能使用英文字母,數字和下劃線,首個字元不能以數字開頭。
  • 中間不能有空格,可以使用下劃線(_)。
  • 不能使用标點符号。
  • 不能使用bash裡的關鍵字(可用help指令檢視保留關鍵字)。
my_name="wangwudang"
a=11      

  除了顯式地直接指派,還可以用語句給變量指派

for file in `ls /etc/cron.d`
或
for file in $(ls      

  2、使用變量

  使用一個定義過的變量,隻要在變量名前面加美元符号即可

  變量名外面的花括号是可選的,加不加都行,加花括号是為了幫助解釋器識别變量的邊界。建議所有的變量都加上花括号。

方式一:
echo $my_name
方式二:
echo      

  3、隻讀變量

  使用 readonly 指令可以将變量定義為隻讀變量,隻讀變量的值不能被改變。

  test.sh

#!/bin/bash
my_country="China"
readonly my_country
my_country="America"      

  運作腳本會報錯

test.sh: line4: my_country: Thisis.

  4、删除變量

  使用 unset 指令可以删除變量,變量被删除後不能再次使用。unset 指令不能删除隻讀變量。

unset variable_name      

  執行個體

#!/bin/bash
my_country="China"
unset my_country
echo      

  運作後沒有任何輸出

  5、變量類型

  三種變量

  • 局部變量局部變量在腳本或指令中定義,僅在目前shell執行個體中有效,其他shell啟動的程式不能通路局部變量
  • 環境變量所有的程式,包括shell啟動的程式,都能通路環境變量,有些程式需要環境變量來保證其正常運作。必要的時候shell腳本也可以定義環境變量
  • shell變量shell變量是由shell程式設定的特殊變量。shell變量中有一部分是環境變量,有一部分是局部變量,這些變量保證了shell的正常運作

   6、變量延伸使用

  

shell掃盲
變量内容符合舊字元串,則全部的舊字元串會被字元串取代
proj="spot-trade"
echo ${proj//-/_}      

三、shell字元串

  字元串是shell程式設計中最常用最有用的資料類型(除了數字和字元串,也沒啥其它類型好用了),字元串可以用單引号,也可以用雙引号,也可以不用引号。

  1、單引号

str='this is a string'      

  單引号的限制

  • 單引号裡的任何字元都會原樣輸出,單引号字元串中的變量是無效的;
  • 單引号字串中不能出現單獨一個的單引号(對單引号使用轉義符後也不行),但可成對出現,作為字元串拼接使用

  2、雙引号

  雙引号的優點

  • 雙引号裡可以有變量
  • 雙引号裡可以出現轉義字元

  3、拼接字元串

greeting="hello, "${your_name}" !"      

  4、擷取字元串長度

string="abcd"
echo ${#string} #輸出 4      

  5、提取子字元串

以下執行個體從字元串第 2 個字元開始截取 4 個字元:

string="mybook is a good book"
echo ${string:1:4} # 輸出 yboo      

注意:第一個字元的索引值為 0。

  5、查找子字元串

  查找字元 i 或 o 的位置(哪個字母先出現就計算哪個):

string="mybook is a good book"
echo `expr index "$string" io` # 輸出 4      

四、shell數組

  bash支援一維數組(不支援多元數組),并且沒有限定數組的大小。

  類似于 C 語言,數組元素的下标由 0 開始編号。擷取數組中的元素要利用下标,下标可以是整數或算術表達式,其值應大于或等于 0

  1、定義數組

數組名=(值1 值2 ... 值n)      

  執行個體

array_name=(value0 value1 value2 value3)

或者
array_name=(
value0
value1
value2
value3
)      
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen      

  可以不使用連續的下标,而且下标的範圍沒有限制

  2、讀取數組

  讀取數組元素值的一般格式是:

${數組名[下标]}      

  例如:

valuen=${array_name[n]}      

@ 符号可以擷取數組中的所有元素,例如:

echo      

  3、擷取數組的長度

  擷取數組長度的方法與擷取字元串長度的方法相同

# 取得數組元素的個數
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得數組單個元素的長度
lengthn=${#array_name[n]}      

五、shell的注釋

  1、單行注釋

  以 # 開頭的行就是注釋,會被解釋器忽略

  2、多行注釋

  多行注釋還可以使用以下格式(EOF可以換成其他字元)

:<<EOF
注釋内容...
注釋内容...
注釋内容...
EOF      

六、shell傳參

  執行 Shell 腳本時,向腳本傳遞參數,腳本内擷取參數的格式為:$n。n 代表一個數字,1 為執行腳本的第一個參數,2 為執行腳本的第二個參數,以此類推……

  test.sh

#!/bin/bash

echo "Shell 傳遞參數執行個體!";
echo "執行的檔案名:$0";
echo "第一個參數為:$1";
echo "第二個參數為:$2";
echo "第三個參數為:$3";      
執行腳本:sh test.sh 1 2 3
執行腳本結果如下      
Shell 傳遞參數執行個體!
執行的檔案名:test.sh
第一個參數為:1
第二個參數為:2
第三個參數為:3      

  處理參數的其他特殊字元

  

shell掃盲

 $* 與 $@ 差別: 

  • 相同點:都是引用所有參數。
  • 不同點:隻有在雙引号中展現出來。假設在腳本運作時寫了三個參數 1、2、3,,則 " * " 等價于 "1 2 3"(傳遞了一個參數),而 "@" 等價于 "1" "2" "3"(傳遞了三個參數)。

七、shell運算符

  1、算數運算符

  

shell掃盲

  注意:條件表達式要放在方括号之間,并且要有空格,例如: [$a==$b] 是錯誤的,必須寫成 [ $a == $b ]。

  • 乘号(*)前邊必須加反斜杠(\)才能實作乘法運算; 
  • if...then...fi 是條件語句,後續将會講解。
  • 在 MAC 中 shell 的 expr 文法是:$((表達式)),此處表達式中的 "*" 不需要轉義符号 "\" 。

  2、關系運算符

  關系運算符隻支援數字,不支援字元串,除非字元串的值是數字。

  

shell掃盲

   3、布爾運算符

shell掃盲

  4、字元串運算符 

  

shell掃盲

  5、檔案測試運算符

  

shell掃盲

  其他檢查符: 

  • -S: 判斷某檔案是否 socket
  • -L: 檢測檔案是否存在并且是一個符号連結

八、Shell printf 指令

  printf 指令模仿 C 程式庫(library)裡的 printf() 程式。

  printf 由 POSIX 标準所定義,是以使用 printf 的腳本比使用 echo 移植性好。

預設 printf 不會像 echo 自動添加換行符,我們可以手動添加 \n。

printf  format-string      

  參數說明:

  • 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 都是格式替代符,%s 輸出一個字元串,%d 整型輸出,%c 輸出一個字元,%f 輸出實數,以小數形式輸出。

%-10s 指一個寬度為 10 個字元(- 表示左對齊,沒有則表示右對齊),任何字元都會被顯示在 10 個字元寬的字元内,如果不足則自動以空格填充,超過也會将内容全部顯示出來。

%-4.2f 指格式化為小數,其中 .2      

  printf 的轉義序列

\a    警告字元,通常為ASCII的BEL字元
\b    後退
\c    抑制(不顯示)輸出結果中任何結尾的換行字元(隻在%b格式訓示符控制下的參數字元串中有效),而且,任何留在參數裡的字元、任何接下來的參數以及任何留在格式字元串中的字元,都被忽略
\f    換頁(formfeed)
\n    換行
\r    回車(Carriage return)
\t    水準制表符
\v    垂直制表符
\\    一個字面上的反斜杠字元
\ddd    表示1到3位數八進制值的字元。僅在格式字元串中有效
\0ddd    表示1到3位的八進制值字元      

九、流程控制

  1、if語句

    1)最簡單的if fi
if condition
then
    command1 
    command2
    ...
    commandN 
fi      
    2)if else
if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi      
    3)if else-if else 
if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi      

  2、for循環

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done      

  寫成一行

for var in item1 item2 ... itemN; do command1; command2… done;      

  3、while語句

  while 循環用于不斷執行一系列指令,也用于從輸入檔案中讀取資料

while condition
do
    command
done      

  4、無限循環

無限循環文法格式:

while :
do
    command
done      

或者

while true
do
    command
done      

或者

for      

  5、until循環

  until 循環執行一系列指令直至條件為 true 時停止。

  until 循環與 while 循環在處理方式上剛好相反。

  一般 while 循環優于 until 循環,但在某些時候—也隻是極少數情況下,until 循環更加有用

until condition
do
    command
done      

  6、case ... esac

  case ... esac 為多選擇語句,與其他語言中的 switch ... case 語句類似,是一種多分枝選擇結構。

  • 每個 case 分支用右圓括号開始
  • 用兩個分号 ;; 表示 break,即執行結束,跳出整個 case ... esac 語句
  • esac(就是 case 反過來)作為結束标記。

  可以用 case 語句比對一個值與一個模式,如果比對成功,執行相比對的指令

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac      

  case 工作方式如上所示,取值後面必須為單詞 in,每一模式必須以右括号結束。取值可以為變量或常數,比對發現取值符合某一模式後,其間所有指令開始執行直至 ;;。

  取值将檢測比對的每一個模式。一旦模式比對,則執行完比對模式相應指令後不再繼續其他模式。如果無一比對模式,使用星号 * 捕獲該值,再執行後面的指令。

  7、跳出循環

  在循環過程中,有時候需要在未達到循環結束條件時強制跳出循環,Shell使用兩個指令來實作該功能:break和continue。

    1)break

break指令允許跳出所有循環(終止執行後面的所有循環)

    2)continue

continue指令與break指令類似,隻有一點差别,它不會跳出所有循環,僅僅跳出目前循環。

   8、for循環和while的差別

    1)使用場景不同
  • 知道執行次數的時候一般用for
  • 條件循環時一般用while
    2)兩種循環造成死循環的差別
  • while循環裡的條件被看成表達式,是以,當用while構造死循環時,裡面的TRUE實際上被看成永遠為真的表達式,這種情況容易産生混淆,有些工具軟體如PC-Lint就會認為出錯了,是以構造死循環時,最好使用for(;;)來進行。
    3)兩種循環在普通循環時的差別:
  • 對一個數組進行循環時,一般來說,如果每輪循環都是在循環處理完後才講循環變量增加的話,使用for循環比較友善。
  • 如果循環處理的過程中就要将循環變量增加時,則使用while循環比較友善。

  還有在使用for循環語句時,如果裡面的循環條件很長,可以考慮用while循環進行替代,使代碼的排版格式好看一些。

  用法:

  • for循環可以設定次數,while循環條件滿足沒有次數限制。

十、函數

  1、定義函數

[ function ] funname [()]

{

    action;

    [return int;]

}      

  說明:

  • 可以帶function fun() 定義,也可以直接fun() 定義,不帶任何參數。
  • 參數傳回,可以顯示加:return 傳回,如果不加,将以最後一條指令運作結果,作為傳回值。 return後跟數值n(0-255)

  2、執行函數

  執行輸入函數名即可調用函數

funcname      

  函數傳回值在調用該函數後通過 $? 來獲得。

  注意:所有函數在使用前必須定義。這意味着必須将函數放在腳本開始部分,直至shell解釋器首次發現它時,才可以使用。調用函數僅使用其函數名即可。

十、shell輸入/輸出重定向

  大多數 UNIX 系統指令從你的終端接受輸入并将所産生的輸出發送回到您的終端。一個指令通常從一個叫标準輸入的地方讀取輸入,預設情況下,這恰好是你的終端。同樣,一個指令通常将其輸出寫入到标準輸出,預設情況下,這也是你的終端。

  1、正常重定向

  

shell掃盲

  需要注意的是檔案描述符 0 通常是标準輸入(STDIN),1 是标準輸出(STDOUT),2 是标準錯誤輸出(STDERR)。  

  2、特殊重定向Here Document

  Here Document 是 Shell 中的一種特殊的重定向方式,用來将輸入重定向到一個互動式 Shell 腳本或程式。

command << delimiter
    document
delimiter      

  它的作用是将兩個 delimiter 之間的内容(document) 作為輸入傳遞給 command。

  注意:

  • 結尾的delimiter 一定要頂格寫,前面不能有任何字元,後面也不能有任何字元,包括空格和 tab 縮進。
  • 開始的delimiter前後的空格會被忽略掉。

  3、/dev/null 檔案(黑洞)

  如果希望執行某個指令,但又不希望在螢幕上顯示輸出結果,那麼可以将輸出重定向到 /dev/null:

command > /dev/null      

  /dev/null 是一個特殊的檔案,寫入到它的内容都會被丢棄;如果嘗試從該檔案讀取内容,那麼什麼也讀不到。但是 /dev/null 檔案非常有用,将指令的輸出重定向到它,會起到"禁止輸出"的效果。

  如果希望屏蔽 stdout 和 stderr,可以這樣寫:

command > /dev/null 2>&1      

十一、shell腳本間調用

  和其他語言一樣,Shell 也可以包含外部腳本。這樣可以很友善的封裝一些公用的代碼作為一個獨立的檔案。

  Shell 檔案包含的文法格式如下:

. filename   # 注意點号(.)和檔案名中間有一空格

或

source filename      

  執行個體

 test1.sh 

#!/bin/bash

url=      

test2.sh

#!/bin/bash


#使用 . 号來引用test1.sh 檔案
. ./test1.sh

# 或者使用以下包含檔案代碼
# source ./test1.sh

echo "我的部落格園位址:$url"      

  執行test2.sh: 

bash test2.sh