1. 程式人生 > >二十八、linux下的shell指令碼(基本)

二十八、linux下的shell指令碼(基本)

先說明以下內容來自: http://c.biancheng.net/cpp/shell/ ,C語言中文網,請大家支援原作,點選連結檢視。

我寫下來只是作為筆記,如果侵權,請留言,立馬刪除。

Shell是一種指令碼語言,那麼,就必須有直譯器來執行這些指令碼,常見的指令碼直譯器有:

bash:是Linux標準預設的shell。bash由Brian
Fox和Chet Ramey共同完成,是BourneAgain Shell的縮寫,內部命令一共有40個。

sh:由Steve Bourne開發,是Bourne Shell的縮寫,sh
是Unix 標準預設的shell。

另外還有:ash、 csh、 ksh等。

常見的程式語言分為兩類:一個是編譯型語言,如:c/c++/java等,它們遠行前全部一起要經過編譯器的編譯。另一個解釋型語言,執行時,需要使用直譯器一行一行地轉換為程式碼,如:awk, perl, python與shell等。

Shell 經過了POSIX的標準化,所以它是可以在不同的linux系統上進行移植。

關於註釋的問題: 在shell中使用#進行註釋,注意,sh裡面沒有多行註釋,只能每一行加一個#號;

第一個shell指令碼程式:

#!/bin/bash
# 上面中的 #! 是一種約定標記, 它可以告訴系統這個指令碼需要什麼樣的直譯器來執行;

echo "Hello, world!"

變數:

定義變數:

country="China"
Number=100

注意: 1,變數名和等號之間不能有空格;

2,首個字元必須為字母(a-z,A-Z)。

3, 中間不能有空格,可以使用下劃線(_)。

4, 不能使用標點符號。

5, 不能使用bash裡的關鍵字(可用help命令檢視保留關鍵字)。

使用變數:

只需要在一個定義過的變數前面加上美元符號 $ 就可以了, 另外,對於變數的{} 是可以選擇的,,它的目的為幫助直譯器識別變數的邊界.

country="China"

echo $country
echo ${country}
echo "I love my ${country}abcd!"   
#這個需要有{}的;

重定義變數: 直接把變數重新像開始定義的那樣子賦值就可以了:

country="China"
country="ribenguizi"

只讀變數: 用 readonly 命令 可以把變數字義為只讀變數。

readonly country="China"
#或
country="China"
readonly country

刪除變數: 使用unset命令可以刪除變數,但是不能刪除只讀的變數。用法:

unset variable_name

變數型別
執行shell時,會同時存在三種變數:
1) 區域性變數
區域性變數在指令碼或命令中定義,僅在當前shell例項中有效,其他shell啟動的程式不能訪問區域性變數。
2) 環境變數
所有的程式,包括shell啟動的程式,都能訪問環境變數,有些程式需要環境變數來保證其正常執行。必要的時候shell指令碼也可以定義環境變數。
3) shell變數
shell變數是由shell程式設定的特殊變數。shell變數中有一部分是環境變數,有一部分是區域性變數,這些變數保證了shell的正常執行

特殊變數:
在這裡插入圖片描述
$* 和 [email protected] 的區別為: $* 和 [email protected] 都表示傳遞給函式或指令碼的所有引數,不被雙引號(" “)包含時,都以”$1" “ 2 " " 2" … " n” 的形式輸出所有引數。但是當它們被雙引號(" “)包含時,”$*" 會將所有的引數作為一個整體,以"$1 $2 … n " " n"的形式輸出所有引數;" @" 會將各個引數分開,以"$1" “ 2 " " 2" … " n” 的形式輸出所有引數。

$? 可以獲取上一個命令的退出狀態。所謂退出狀態,就是上一個命令執行後的返回結果。退出狀態是一個數字,一般情況下,大部分命令執行成功會返回 0,失敗返回 1。

Shell中的替換
轉義符:

在echo中可以用於的轉義符有:
在這裡插入圖片描述

使用 echo 命令的 –E 選項禁止轉義,預設也是不轉義的; 使用 –n 選項可以禁止插入換行符;

使用 echo 命令的 –e 選項可以對轉義字元進行替換。

另外,注意,經過我的實驗,得到:

echo "\\"        #得到 \
echo -e "\\"   #得到  \

echo "\\\\"        #得到 \\
echo -e "\\"       #得到  \

命令替換:

它的意思就是說我們把一個命令的輸出賦值給一個變數,方法為把命令用反引號(在Esc下方)引起來. 比如:

directory=`pwd`
echo $directory

變數替換:

可以根據變數的狀態(是否為空、是否定義等)來改變它的值.
在這裡插入圖片描述

Shell運算子
算數運算子:

原生bash不支援簡單的數學運算,但是可以通過其他命令來實現,例如 awk 和 expr. 下面使用expr進行; expr是一款表示式計算工具,使用它可以完成表示式的求值操作;
在這裡插入圖片描述
比如:

a=10
b=20
expr $a + $b
expr $a - $b
expr $a \* $b
expr $a / $b
expr $a % $b
a=$b

注意: 1. 在expr中的乖號為:*

  1. 在 expr中的 表示式與運算子之間要有空格,否則錯誤;

  2. 在[ $a == $b ]與[ $a != $b ]中,要需要在方括號與變數以及變數與運算子之間也需要有括號, 否則為錯誤的。(親測過)

關係運算符:

只支援數字,不支援字串,除非字串的值是數字。常見的有:
在這裡插入圖片描述
注意:也別忘記了空格;
布林運算子:
在這裡插入圖片描述

字串運算子:
在這裡插入圖片描述
檔案測試運算子:
檢測 Unix 檔案的各種屬性。

Shell中的字串
單引號的限制:
1.單引號裡的任何字元都會原樣輸出,單引號字串中的變數是無效的;
2.單引號字串中不能出現單引號(對單引號使用轉義符後也不行)。

雙引號的優點:
1.雙引號裡可以有變數
2.雙引號裡可以出現轉義字元

拼接字串:

country="China"
echo "hello, $country"
#也可以
echo "hello, "$country" "

獲取字串長度:

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

提取子字串:

string="alibaba is a great company"
echo ${string:1:4} #輸出liba

查詢子字串:

string="alibaba is a great company"
echo `expr index "$string" is`

處理路經的字串:
例如:當一個路徑為 /home/xiaoming/1.txt時,如何怎麼它的路徑(不帶檔案) 和如何得到它的檔名??

得到檔名使用 bashname命令:

#  引數:
#  -a,表示處理多個路徑;
# -s, 用於去掉指定的檔案的字尾名;

 basename /home/yin/1.txt          -> 1.txt

 basename -a /home/yin/1.txt /home/zhai/2.sh     -> 
1.txt
2.sh basename -s .txt /home/yin/1.txt    -> 1
 basename /home/yin/1.txt .txt       -> 1

得到路徑名(不帶檔名)使用 dirname命令:

引數:沒有啥引數;

//例子:
 dirname /usr/bin/          -> /usr
 dirname dir1/str dir2/str  -> 
dir1
dir2
 dirname stdio.h            -> .

Shell的陣列:
bash支援一維陣列, 不支援多維陣列, 它的下標從0開始編號. 用下標[n] 獲取陣列元素;

定義陣列:

在shell中用括號表示陣列,元素用空格分開。 如:

array_name=(value0 value1 value2 value3)

也可以單獨定義陣列的各個分量,可以不使用連續的下標,而且下標的範圍沒有限制。如:

array_name[0]=value0
array_name[1]=value1
array_name[2]=value2

讀取陣列:

讀取某個下標的元素一般格式為:

${array_name[index]}

讀取陣列的全部元素,用@或*

${array_name[*]}
${array_name[@]}

獲取陣列的資訊:

取得陣列元素的個數:

length=${#array_name[@]}
#或
length=${#array_name[*]}

獲取陣列的下標:

length=${!array_name[@]}
#或
length=${!array_name[*]}

取得陣列單個元素的長度:

lengthn=${#array_name[n]}

printf函式:

它與c語言中的printf相似,不過也有不同,下面列出它的不同的地方:

1.printf 命令不用加括號
2.format-string 可以沒有引號,但最好加上,單引號雙引號均可。
3.引數多於格式控制符(%)時,format-string 可以重用,可以將所有引數都轉換。
4.arguments 使用空格分隔,不用逗號。

下面為例子:

# format-string為雙引號
$ printf "%d %s\n" 1 "abc"
abc
# 單引號與雙引號效果一樣 
$ printf '%d %s\n' 1 "abc" 
abc
# 沒有引號也可以輸出
$ printf %s abcdef
abcdef
# 格式只指定了一個引數,但多出的引數仍然會按照該格式輸出,format-string 被重用
$ printf %s abc def
abcdef
$ printf "%s\n" abc def
abc
def
$ printf "%s %s %s\n" a b c d e f g h i j
a b c
d e f
g h i
j
# 如果沒有 arguments,那麼 %s 用NULL代替,%d 用 0 代替
$ printf "%s and %d \n" 
and 0
# 如果以 %d 的格式來顯示字串,那麼會有警告,提示無效的數字,此時預設置為 0
$ printf "The first program always prints'%s,%d\n'" Hello Shell
-bash: printf: Shell: invalid number
The first program always prints 'Hello,0'
$

Shell中條件語句
if 語句
包括:
1, if [ 表示式 ] then 語句 fi

  1. if [ 表示式 ] then 語句 else 語句 fi

  2. if [ 表示式] then 語句 elif[ 表示式 ] then 語句 elif[ 表示式 ] then 語句 …… fi

例子

a=10
b=20
if [ $a == $b ]
then
   echo "a is equal to b"
else
   echo "a is not equal to b"
fi

另外:if … else 語句也可以寫成一行,以命令的方式來執行,像這樣

if test $[2*3] -eq $[1+5]; then echo 'The two numbers are equal!'; fi;

其中,test 命令用於檢查某個條件是否成立,與方括號([ ])類似。

case …… esac語句

case … esac 與其他語言中的 switch … case 語句類似,是一種多分枝選擇結構。case語句格式如下:

case 值 in
模式1)
    command1
    command2
    command3
    ;;
模式2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac

其中, 1. 取值後面必須為關鍵字 in,每一模式必須以右括號結束。取值可以為變數或常數。匹配發現取值符合某一模式後,其間所有命令開始執行直至 ;;。;; 與其他語言中的 break 類似,意思是跳到整個 case 語句的最後。2. 如果無一匹配模式,使用星號 * 捕獲該值,再執行後面的命令。

Shell 的迴圈語句
for 迴圈

一般格式為:

for 變數 in 列表
do
    command1
    command2
    ...
    commandN
done

注意:列表是一組值(數字、字串等)組成的序列,每個值通過空格分隔。每迴圈一次,就將列表中的下一個值賦給變數。 例如:

順序輸出當前列表的數字:

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

顯示主目錄下以 .bash 開頭的檔案:

#!/bin/bash
for FILE in $HOME/.bash*
do
   echo $FILE
done

while迴圈
一般格式為:

while command
do
   Statement(s) to be executed if command is true
done

例如:

COUNTER=0
while [ $COUNTER -lt 5 ]
do
    COUNTER='expr $COUNTER+1'
    echo $COUNTER
done

until 迴圈
until 迴圈執行一系列命令直至條件為 true 時停止。until 迴圈與 while 迴圈在處理方式上剛好相反。 常用格式為:

until command
do
   Statement(s) to be executed until command is true
done

command 一般為條件表示式,如果返回值為 false,則繼續執行迴圈體內的語句,否則跳出迴圈。

類似地, 在迴圈中使用 break 與continue 跳出迴圈。 另外,break 命令後面還可以跟一個整數,表示跳出第幾層迴圈。

Shell函式
Shell函式必須先定義後使用,定義如下,

function_name () {
    list of commands
    [ return value ]
}

也可以加上function關鍵字:

function function_name () {
    list of commands
    [ return value ]
}

注意:

  1. 呼叫函式只需要給出函式名,不需要加括號。

  2. 函式返回值,可以顯式增加return語句;如果不加,會將最後一條命令執行結果作為返回值。

  3. Shell 函式返回值只能是整數,一般用來表示函式執行成功與否,0表示成功,其他值表示失敗。

  4. 函式的引數可以通過 $n 得到.如:

funWithParam(){
    echo "The value of the first parameter is $1 !"
    echo "The value of the second parameter is $2 !"
    echo "The value of the tenth parameter is ${10} !"
    echo "The value of the eleventh parameter is ${11} !"
    echo "The amount of the parameters is $# !"  # 引數個數
    echo "The string of the parameters is $* !"  # 傳遞給函式的所有引數
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
  1. 像刪除變數一樣,刪除函式也可以使用 unset 命令,不過要加上 .f 選項,如下所示:
unset .f function_name

shell的檔案包含:
Shell 也可以包含外部指令碼,將外部指令碼的內容合併到當前指令碼。使用:

. filename
#或
source filename
  1. 兩種方式的效果相同,簡單起見,一般使用點號(.),但是注意點號(.)和檔名中間有一空格。

  2. 被包含指令碼不需要有執行許可權。