[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