Shell 腳本入門及語法速查 原

[TOC]


1. Hello World

1.1. 基本結構

創建 helloWorld.sh 文件,寫入如下內容:

#!/bin/bash

echo "hello world"

其中 #! 告訴系統其後路徑所指定的程序是解釋此腳本文件的 Shell 程序,常見的 Shell 程序有以下幾類(可通過命令 cat /etc/shells 查看):

  • 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 在日常工作中被廣泛使用,同時也是大多數 Linux 系統默認的 Shell。

執行該 sh 腳本

# 增加可執行權限
➜  chmod u+x helloWorld.sh

# 運行腳本
➜  ./helloWorld.sh
或
➜  sh hellowWorld.sh

1.2. 註釋

單行註釋

  • # 開頭的行是註釋

多行註釋

  • 方式一:用一對 {} 括起來,定義成一個函數,沒有地方調用即達到註釋的效果。

  • 方式二:

    :<<EOF
    註釋內容...
    註釋內容...
    註釋內容...
    EOF
    

2. 基本語法

2.1. 變量

  • 變量定義

    • 變量名建議大寫;
    • 有效字符僅能包含字母、數字、下劃線,首個字符不能以數字開頭;
    • = 兩邊不能有空格;
    • 不能使用標點符號;
    • 不能使用 bash 裏的關鍵字(可用 help 命令查看保留關鍵字)。

    如下示例:

    VAR1="whoru"
    VAR2=100
    var3=/data/www
    var4_name="root"
    
  • 訪問變量 $VAR1$(var1),其中,加花括號是爲了幫助解釋器識別變量的邊界。

  • 設置變量只讀 readonly VAR1

  • 刪除變量(不適用於只讀變量!unset VAR1

2.2. 字符串

  • 值用雙引號 "" 或單引號 '' 表示
    • 單引號單限制:
      • 單引號裏的任何字符都會原樣輸出;
      • 單引號字符串中的變量是無效的;
    • 雙引號的優點:
      • 雙引號裏可以有變量;
      • 雙引號裏可以出現轉義字符;
  • 其它
    # 字符串拼接 
    name="xiaoming"
    var2="hello, "$name # 輸出 hello, xiaoming
    
    # 獲取字符串長度
    string="abcd"
    echo ${#string} # 輸出 4
    
    # 提取子字符串
    msg="zhangsan is a good man"
    echo ${msg:1:4} # 輸出 hang
    

2.3. 數組

  • bash 支持一維數組(不支持多維數組),並且沒有限定數組的大小。

  • 數組元素的下標由 0 開始,獲取數組元素要用到下標。

  • 定義:

    array1=(value0 value1 value2 value3)
    
    或
    
    array2[0]=value0
    array2[1]=value1
    array2[2]=value2
    
  • 讀取

    # 指定下標的元素
    echo ${array2[2]}; // 輸出 value2
    
    # 獲取數組所有元素
    echo ${array2[*]}; // 輸出 value0 value1 value2
    echo ${array2[@]}
    
  • 獲取數組元素個數

    echo ${#array2[@]}; // 輸出 3
    echo ${#array2[*]};
    
  • 取得數組中指定下標元素的字符長度

    echo ${#array2[2]};
    

2.4. 傳遞參數

在執行 Shell 腳本時,可以向腳本傳遞參數,腳本內獲取參數的格式爲 $n,這裏的 n 指傳遞給腳本的第 n 個參數。

如下腳本文件 demo.sh

#!/bin/bash

echo "執行的文件名:$0";
echo "第一個參數爲:$1";
echo "第二個參數爲:$2";
echo "第三個參數爲:$3";

執行該文件,並傳遞參數,如下:

➜  ./demo3.sh param1 param2 param3
執行的文件名:./demo3.sh
第一個參數爲:param1
第二個參數爲:param2
第三個參數爲:param3

其中,$0 是一個特殊變量,代表當前腳本文件名,還有幾個類似的變量如下:

變量說明
$#傳遞給腳本的參數個數。
$*以一個單字符串的形式顯示所有向腳本傳遞的參數,如 "$1 $2 ... $n"
$@$* 相同,但是使用引號把每個參數包裹起來,如 "$1" "$2" ... "$n"
$?最後一個執行的命令的退出狀態:0 正常;1 或其它任何值,表示有錯誤
$$腳本運行的當前進程ID號
$!最後一個後臺命令的進程號。

3. 運算符

3.1. 算數運算符

原生 bash 不支持簡單的數學運算,但是可以通過其他命令來實現,例如 awk 和 expr,其中 expr 最常用。

假定有兩個變量: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。
==用於比較兩個數字是否相同[ $a == $b ] 返回 false。
!=用於比較兩個數字是否不相同[ $a != $b ] 返回 true。

注意

  • 表達式和運算符之間要有空格,如 2+2 是錯誤的,必須寫成 2 + 2;
  • 完整的表達式要被反引號 ` ` 包裹起來;

3.2. 關係運算符

關係運算符只支持數字,不支持字符串,除非字符串的值是數字。

假定有兩個變量:a=10 b=20

運算符說明舉例
-eq檢測兩個數是否相等[ $a -eq $b ] 返回 false。
-ne檢測兩個數是否不相等[ $a -ne $b ] 返回 true。
-gt檢測左邊的數是否大於右邊的[ $a -gt $b ] 返回 false。
-lt檢測左邊的數是否小於右邊的[ $a -lt $b ] 返回 true。
-ge檢測左邊的數是否大於等於右邊的[ $a -ge $b ] 返回 false。
-le檢測左邊的數是否小於等於右邊的[ $a -le $b ] 返回 true。

3.3. 布爾操作符

假定有兩個變量:a=10 b=20

運算符說明舉例
!非運算,表達式爲 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。

3.4. 邏輯運算符

假定有兩個變量:a=10 b=20

運算符說明舉例
&&邏輯的 AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false
||邏輯的 OR[[ $a -lt 100 || $b -gt 100 ]] 返回 true

3.5. 字符串運算符

假定有兩個變量:a="abc" b="efg"

運算符說明舉例
=檢測兩個字符串是否相等[ $a = $b ] 返回 false。
!=檢測兩個字符串是否不相等[ $a != $b ] 返回 true。
-z檢測字符串長度是否爲 0(空)[ -z $a ] 返回 false。
-n檢測字符串長度是否不爲0(非空)[ -n "$a" ] 返回 true。
str檢測字符串是否爲不爲空[ $a ] 返回 true。

3.6. 文件測試運算符

運算符說明(如果是,則返回 true)舉例
-b檢測文件是否是塊設備文件[ -b $file ]
-c檢測文件是否是字符設備文件[ -c $file ]
-d檢測文件是否是目錄[ -d $file ]
-f檢測文件是否是普通文件(既不是目錄,也不是設備文件)[ -f $file ]
-g檢測文件是否設置了 SGID 位[ -g $file ]
-k檢測文件是否設置了粘着位(Sticky Bit)[ -k $file ]
-p檢測文件是否是有名管道[ -p $file ]
-u檢測文件是否設置了 SUID 位[ -u $file ]
-r檢測文件是否可讀[ -r $file ]
-w檢測文件是否可寫[ -w $file ]
-x檢測文件是否可執行[ -x $file ]
-s檢測文件是否爲非空(文件大小是否大於0)文件[ -s $file ]
-e檢測文件(包括目錄)是否存在[ -e $file ]

4. 流程控制

4.1. if 語句

大多使用關係運算符檢查關係

# 語法格式
if condition1
then
    command1
    ...
elif condition2
then
    command2
else
    commandN
fi

4.2. case 語句

# 語法格式
case 值 in
    模式1)
        command1
        command2
        ...
        commandN
        ;;
    模式2)
        command1
        command2
        ...
        commandN
        ;;
    *)
        commandDefault
        ;;
esac

4.3. while 語句

用於不斷執行一系列命令,也用於從輸入文件中讀取數據;命令通常爲測試條件。其格式爲:

# 語法格式
while condition
do
    command
done

4.4. until 循環

執行一系列命令直至條件爲 true 時停止,它與 while 循環 在處理方式上剛好相反。

# 語法格式
until condition
do
    command
done

4.5. for 循環

# 語法格式
for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

4.6. 無限循環

# 語法1
while :
do
    command
done

# 語法2
while true
do
    command
done

# 語法3
for (( ; ; ))

4.7. 退出循環

  • break 跳出整個循環,執行循環體後面的代碼,支持 break n 退出多層嵌套循環
  • continue 結束當前循環,同樣支持 continue n 退出多層

5. 輸入、輸出重定向

5.1. 命令列表

命令說明
command > file將輸出結果重定向到 file。
command < file將輸入重定向到 file。
command >> file將輸出以追加的方式重定向到 file。
n > file將文件描述符爲 n 的文件重定向到 file。
n >> file將文件描述符爲 n 的文件以追加的方式重定向到 file。
n >& m將輸出文件 m 和 n 合併。
n <& m將輸入文件 m 和 n 合併。
<< tag將開始標記 tag 和結束標記 tag 之間的內容作爲輸入。

關於文件描述符:

  • 0 通常是標準輸入(STDIN),Unix程序默認從 stdin 讀取數據。
  • 1 標準輸出(STDOUT),Unix程序默認向 stdout 輸出數據。
  • 2 標準錯誤輸出(STDERR),Unix程序會向 stderr 流中寫入錯誤信息。

示例:

# 將 stdout 和 stderr 合併後重定向到 file
➜  command > file 2>&1

5.2. /dev/null 文件

這是一個特殊的文件,寫入到它的內容都會被丟棄;如果嘗試從該文件讀取內容,也什麼也讀不到。我們通常將命令的輸出重定向到它,起到“禁止輸出”的效果。

如:

# 屏蔽 stdout 和 stderr
➜  command > /dev/null 2>&1

5.3. Here 文檔

# 將兩個 delimiter 之間的內容(document) 作爲輸入傳遞給 command。
command << delimiter
document
delimiter

說明:

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

6. 函數

6.1. 基本語法

[ function ] funcName [()] {

    command;

    [return int;]

}

說明:

  • function 關鍵字非必須;
  • 如果該函數不傳入變量,這函數名的後面的括號可以不加;
  • return 非必須;默認返回最後一條命令的執行結果;
  • 調用函數僅使用其函數名,如 funcName
  • 所有函數在使用前必須定義,即函數調用必須要在函數聲明之後。

6.2. 函數參數

func() {
    echo "第一個參數爲 $1 !"
    echo "第二個參數爲 $2 !"
    ...
    echo "第十個參數爲 ${10} !"
    ...
}

# 調用並傳參
func param1 param2 param3

說明

  • 在函數體內部,通過 $n 的形式來獲取參數的值,例如:$1 表示第一個參數,$2 表示第二個參數;
  • 當 n >= 10 時,需要使用 ${n} 來獲取參數。

7. 其它

7.1. echo 命令

用於字符串的輸出,基本格式 echo string

使用示例:

# 顯示普通字符
echo "It is a test" # 輸出 It is a test

# 顯示轉義字符
echo "\"It is a test\"" # 輸出 "It is a test"

# 顯示變量
#!/bin/sh
NAME="xiaoming" 
echo "$NAME It is a test" # 輸出 xiaoming is a test

# 顯示換行
echo -e "OK! \n" # -e 開啓轉義
echo "It is a test"

# 顯示不換行
echo -e "OK! \c" # -e 開啓轉義 \c 不換行
echo "It is a test"

# 顯示結果定向至文件
echo "It is a test" > myfile

# 顯示命令執行結果
echo `date`

7.2. printf 命令

模仿 C 程序庫(library)裏的 printf() 程序,主要用於格式化輸出。

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

其基本語法格式爲:

printf  format-string  [arguments...]

說明:

  • format-string 爲格式控制字符串
  • arguments 爲參數列表。

示例:

➜  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位小數。

更多使用示例:

# 沒有引號也可以輸出
➜  printf %s abcdef

# 格式只指定了一個參數,但多出的參數仍然會按照該格式輸出,format-string 被重用
➜  printf %s abc def
abcdef

➜  printf "%s\n" abc def
abc
def

# 如果沒有 arguments,那麼 %s 用NULL代替,%d 用 0 代替
➜  printf "%s and %d \n" 
 and 0

7.3. test 命令

用於檢查某個條件是否成立,它可以進行數值、字符和文件三個方面的測試(詳見第3節對應的運算符部分)。

基本使用示例:

cd /bin
if test -e ./bash
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi

7.4. 包含文件

被包含的文件不需要可執行權限。

# 方式一
. another_file.sh

# 方式二
source another_file.sh

更新:https://github.com/whorusq/linux-learning/edit/master/shell_basic_guide.md

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章