# 運算符優先級
在腳本中,運算執行的順序被稱為*優先級*: 高優先級的操作會比低優先級的操作先執行。[^1]
**表 8-1. 運算符優先級(從高到低)**
| 運算符 | 含義 | 注解 |
|:------------|:--------------|:------------|
| var++ var-- | 后綴自增/自減 | C風格運算符 |
| ++var --var | 前綴自增/自減 | |
| | | |
| ! ~ | 按位取反/邏輯取反 | 對每一比特位取反/對邏輯判斷的結果取反 |
| | | |
| \*\* | 冪運算 | 算數運算符 |
| \* / % | 乘, 除, 取余 | 算數運算符 |
| + - | 加, 減 | 算數運算符 |
| | | |
| << >> | 左移, 右移 | 比特位運算符|
| | | |
| -z -n | 一元比較 | 字符串是/否為空 |
| -e -f -t -x, etc | 一元比較 | 文件測試 |
| -lt -gt -le -ge <= >= | 復合比較 | 字符串/整數比較 |
| -nt -ot -ef | 復合比較 | 文件測試 |
| | | |
| & | AND(按位與) | 按位與操作 |
| ^ | XOR(按位異或) | 按位異或操作|
| \| | OR(按位或) | 按位或操作 |
| | | |
| && -a | AND(邏輯與) | 邏輯與, 復合比較 |
| \|\| -o | OR(邏輯或) | 邏輯或, 復合比較 |
| | | |
| ? : | if/else三目運算符| C風格運算符 |
| = | 賦值 | 不要與test中的等號混淆 |
| \*= /= %= += -= <<= >>= &= | 賦值運算 | 先運算后賦值 |
| | | |
| , | 逗號運算符 | 連接一系列語句 |
實際上,你只需要記住以下規則就可以了:
- 先乘除取余,后加減,與算數運算相似
- 復合邏輯運算符,&&, ||, -a, -o 優先級較低
- 優先級相同的操作按*從左至右*順序求值
現在,讓我們利用運算符優先級的知識來分析一下*Fedora Core Linux*中的`/etc/init.d/functions`文件。
```
while [ -n "$remaining" -a "$retry" -gt 0 ]; do
# 初看之下很恐怖...
# 分開來分析
while [ -n "$remaining" -a "$retry" -gt 0 ]; do
# --condition 1-- ^^ --condition 2-
# 如果變量"$remaining" 長度不為0
#+ 并且AND (-a)
#+ 變量 "$retry" 大于0
#+ 那么
#+ [ 方括號表達式 ] 返回成功(0)
#+ while-loop 開始迭代執行語句。
# ==============================================================
# "condition 1" 和 "condition 2" 在 AND之前執行,為什么?
# 因為AND(-a)優先級比-n,-gt來得低,邏輯與會在最后求值。
#################################################################
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
# 同樣,分開來分析
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
# --condition 1--------- ^^ --condition 2-----
# 如果文件"/etc/sysconfig/i18n" 存在
#+ 并且AND (-a)
#+ 變量 $NOLOCALE 長度不為0
#+ 那么
#+ [ 方括號表達式 ] 返回成功(0)
#+ 執行接下來的語句。
#
# 和之前的情況一樣,邏輯與AND(-a)最后求值。
# 因為在方括號測試結構中,邏輯運算的優先級是最低的。
# ==============================================================
# 注意:
# ${NOLOCALE:-} 是一個參數擴展式,看起來有點多余。
# 但是, 如果 $NOLOCALE 沒有提前聲明, 它會被設成null,
# 在某些情況下,這會有點問題。
```
> 為了避免在復雜比較運算中的錯誤,可以把運算分散到幾個括號結構中。
> ```
> if [ "$v1" -gt "$v2" -o "$v1" -lt "$v2" -a -e "$filename" ]
> # 這樣寫不清晰...
>
> if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]]
> # 好多了 -- 把邏輯判斷分散到多個組之中
> ```
[^1]: Precedence(優先級),根據上下文,與priority含義相近。
- 第一部分 初見shell
- 1. 為什么使用shell編程
- 2. 和Sha-Bang(#!)一起出發
- 2.1 調用一個腳本
- 2.2 牛刀小試
- 第二部分 shell基礎
- 3. 特殊字符
- 4. 變量與參數
- 4.1 變量替換
- 4.2 變量賦值
- 4.3 Bash弱類型變量
- 4.4 特殊變量類型
- 5. 引用
- 5.1 引用變量
- 5.2 轉義
- 6. 退出與退出狀態
- 7. 測試
- 7.1 測試結構
- 7.2 文件測試操作
- 7.3 其他比較操作
- 7.4 嵌套 if/then 條件測試
- 7.5 牛刀小試
- 8. 運算符相關話題
- 8.1 運算符
- 8.2 數字常量
- 8.3 雙圓括號結構
- 8.4 運算符優先級
- 第三部分 shell進階
- 10. 變量處理
- 10.1 字符串處理
- 10.1.1 使用 awk 處理字符串
- 10.1.2 參考資料
- 10.2 參數替換
- 11. 循環與分支
- 11.1 循環
- 11.2 嵌套循環
- 11.3 循環控制
- 11.4 測試與分支
- 12. 命令替換
- 13. 算術擴展
- 14. 休息時間
- 第五部分 進階話題
- 19. 嵌入文檔
- 20. I/O 重定向
- 20.1 使用 exec
- 20.2 重定向代碼塊
- 20.3 應用程序
- 22. 限制模式的Shell
- 23. 進程替換
- 26. 列表結構
- 25. 別名