Skip to content

Latest commit

 

History

History
612 lines (419 loc) · 16.7 KB

ch8-1.md

File metadata and controls

612 lines (419 loc) · 16.7 KB

8.1. Operators

第八章第一節:運算子

assignment

賦值

variable assignment

變數賦值

Initializing or changing the value of a variable

初始化或變更一變數值。

= All-purpose assignment operator, which works for both arithmetic and string assignments.

等號 "=" 為多功能的賦值運算子,算術運算與字串賦值皆適用。

var=27
category=minerals  # No spaces allowed after the "=".
                   # 等號 "=" 後面不允許接空白字元。

Note: Do not confuse the "=" assignment operator with the = test operator.

注意:變數賦值運算子的等號 "=",別跟 test 指令運算子的等號 "=" 混淆了。

#   =  as a test operator
# 作為一個 test 指令運算子的等號 =

if [ "$string1" = "$string2" ]
then
   command
fi

#  if [ "X$string1" = "X$string2" ] is safer,
#                                   這個寫法比較安全,
#  to prevent an error message should one of the variables be empty.
#  以防止發生其中一個變數為空字串的錯誤訊息。
#  (The prepended "X" characters cancel out.)
#  (前置一個 "X" 字元將有抵銷此種錯誤的效果。)

arithmetic operators

算術運算子

plus

加號

- minus

- 減號

* multiplication

* 乘號

/ division

/ 除號

** exponentiation

** 乘冪符號

# Bash, version 2.02, introduced the "**" exponentiation operator.
# Bash 在 2.02 版之後 (含 2.02 版),導入乘冪符號 "**" 算術運算子支援。

let "z=5**3"    # 5 * 5 * 5
echo "z = $z"   # z = 125

% modulo, or mod (returns the remainder of an integer division operation)

% 模除或 mod (回傳整數除法中的餘數)

bash$ expr 5 % 3
2

5/3 = 1, with remainder 2

5除以3等於1餘2

This operator finds use in, among other things, generating numbers within a specific range (see Example 9-11 and Example 9-15) and formatting program output (see Example 27-16 and Example A-6).

除此之外,這個運算子被發現可用於產生指定範圍內的數字 (詳情請參閱:範例 9-11 與範例 9-15) 以及格式化程式輸出內容 (詳情請參閱:範例 27-16 與範例 A-6)。

It can even be used to generate prime numbers, (see Example A-15).

它甚至可以用來產生質數,(詳情請參閱:範例 A-15)。

Modulo turns up surprisingly often in numerical recipes.

模除常常意外地出現在一些數值訣竅裡。

Example 8-1. Greatest common divisor

範例 8-1. 最大公因數

#!/bin/bash
# gcd.sh: greatest common divisor
#         最大公因數
#         Uses Euclid's algorithm
#         使用歐幾里得算法 (Euclid's algorithm),即輾轉相除法。

#  The "greatest common divisor" (gcd) of two integers
#  兩個整數的最大公因數 (GCD)
#  is the largest integer that will divide both, leaving no remainder.
#  為能夠同時整除兩數的最大正整數。

#  Euclid's algorithm uses successive division.
#  歐幾里得算法使用輾轉相除法。
#    In each pass,
#    在每一回合裡,
#       dividend <---  divisor
#       divisor  <---  remainder
#       被除數   <---  除數
#       除數     <---  餘數
#    until remainder = 0.
#    直到餘數等於 0 為止。
#    The gcd = dividend, on the final pass.
#    則最大公因數等於最後一回合的被除數。
#
#  For an excellent discussion of Euclid's algorithm, see
#  更多關於歐幾里得算法的傑出討論,請參閱
#  Jim Loy's site, http://www.jimloy.com/number/euclids.htm.
#  Jim Loy 的網站, http://www.jimloy.com/number/euclids.htm.


# ------------------------------------------------------
# Argument check
# 引數檢查
ARGS=2
E_BADARGS=85

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` first-number second-number"
  exit $E_BADARGS
fi
# ------------------------------------------------------


gcd ()
{
  dividend=$1             #  Arbitrary assignment.
                          #  任意指定賦值。
  divisor=$2              #! It doesn't matter which of the two is larger.
                          #! 兩者誰大誰小都沒關係。
                          #  Why not?
                          #  為何沒差?

  remainder=1             #  If an uninitialized variable is used inside
                          #  若在 test 的中括號指令裡使用了未初始化的變數,
                          #  test brackets, an error message results.
                          #  則會有錯誤訊息發生。

  until [ "$remainder" -eq 0 ]
  do    #  ^^^^^^^^^^  Must be previously initialized!
        #  ^^^^^^^^^^  必須在這之前已初始化!
    let "remainder = $dividend % $divisor"
    dividend=$divisor     # Now repeat with 2 smallest numbers.
                          # 重複於 2 個最小的數上面。
    divisor=$remainder
  done                    # Euclid's algorithm
                          # 歐幾里得算法

}                         # Last $dividend is the gcd.
                          # 最後一個 $dividend 即為最大公因數。


gcd $1 $2

echo; echo "GCD of $1 and $2 = $dividend"; echo


# Exercises :
# 練習題:
# ---------
# 1) Check command-line arguments to make sure they are integers,
# 1) 檢查命令列參數以確保它們都是整數,
#    and exit the script with an appropriate error message if not.
#    並且,若不是,則帶著一個適當的錯誤訊息退出腳本。
# 2) Rewrite the gcd () function to use local variables.
# 2) 使用區域變數重寫 gcd () 函式。

exit 0

= plus-equal (increment variable by a constant) [38]

' =' *加-等號* (以一常數值遞增變數) [38]

let "var = 5" results in var being incremented by 5.

例如: 'let "var = 5"' 結果為 var 遞增 5。

-= minus-equal (decrement variable by a constant)

'-=' *減-等號* (以一常數值遞減變數)

*= times-equal (multiply variable by a constant)

'*=' 乘-等號 (變數乘以一常數)

let "var *= 4" results in var being multiplied by 4.

例如: 'let "var *= 4"' 結果為 var 被乘以 4.

/= slash-equal (divide variable by a constant)

`'/=' 除-等號 (變數除以一常數)

%= mod-equal (remainder of dividing variable by a constant)

'%=' *模除-等號* (變數除以一常數之 *餘數*)

Arithmetic operators often occur in an expr or let expression.

算術運算子通常出現在 expr 或 let 表示式。

Example 8-2. Using Arithmetic Operations

範例 8-2. 使用算術運算

#!/bin/bash
# Counting to 11 in 10 different ways.
# 以10種不同方法上數至11

n=1; echo -n "$n "

let "n = $n   1"   # let "n = n   1"  also works.
                   # let "n = n   1"  也有同樣效果。
echo -n "$n "


: $((n = $n   1))
#  ":" necessary because otherwise Bash attempts
#  ":" 是必須的,否則 Bash 會企圖
#  to interpret "$((n = $n   1))" as a command.
#  把 "$((n = $n   1))" 的運算結果當成一個指令來執行。
echo -n "$n "

(( n = n   1 ))
#  A simpler alternative to the method above.
#  上一段之另一種較簡單的寫法,
#  Thanks, David Lombard, for pointing this out.
#  感謝 David Lombard 提供這一招。
echo -n "$n "

n=$(($n   1))
echo -n "$n "

: $[ n = $n   1 ]
#  ":" necessary because otherwise Bash attempts
#  ":" 是必要的,否則 Bash 會企圖
#  to interpret "$[ n = $n   1 ]" as a command.
#  把 "$[ n = $n   1 ]" 的運算結果當成一個指令來執行。
#  Works even if "n" was initialized as a string.
#  就算 "n" 被初始成一字串,仍可動作。
echo -n "$n "

n=$[ $n   1 ]
#  Works even if "n" was initialized as a string.
#  就算 "n" 被初始成一字串,仍可動作。
#* Avoid this type of construct, since it is obsolete and nonportable.
#* 避免使用此種建構型式,因為它已被淘汰且不可攜。
#  Thanks, Stephane Chazelas.
#  感謝 Stephane Chazelas 提供。
echo -n "$n "

# Now for C-style increment operators.
# 現在來看 C-style 遞增運算子。
# Thanks, Frank Wang, for pointing this out.
# 感謝 Frank Wang 提供這一招。

let "n  "          # let "  n"  also works.
                   # let "  n"  也可以動。
echo -n "$n "

(( n   ))          # ((   n ))  also works.
                   # ((   n ))  也可以動。
echo -n "$n "

: $(( n   ))       # : $((   n )) also works.
                   # : $((   n )) 也可以動。
echo -n "$n "

: $[ n   ]         # : $[   n ] also works
                   # : $[   n ] 也可以動。
echo -n "$n "

echo

exit 0

Note: Integer variables in older versions of Bash were signed long (32-bit) integers, in the range of -2147483648 to 2147483647.

注意:舊版 Bash 裡的整數變數大小類型是 signed long (32-bit) 的整數,其範圍在 -2147483648 to 2147483647.

An operation that took a variable outside these limits gave an erroneous result.

一個讓變數超出此限制範圍的操作,將產生錯誤訊息與錯誤的結果。

echo $BASH_VERSION   #  1.14

a=2147483646
echo "a = $a"        # a = 2147483646
let "a =1"           # Increment "a".
                     # "a" 遞增.
echo "a = $a"        # a = 2147483647
let "a =1"           # increment "a" again, past the limit.
                     # "a" 再遞增一次,進而超出限制。
echo "a = $a"        # a = -2147483648
                     #      ERROR: out of range,
                     #      錯誤:超出範圍,
                     #      and the leftmost bit, the sign bit,
                     #      並且最左邊一 bit, 即 sign bit,
                     #      has been set, making the result negative.
                     #      已被設成 1, 將使結果變成負數。

As of version >= 2.05b, Bash supports 64-bit integers.

在 2.05b 版本之後 (含 2.05b 版), Bash 開始支援 64-bit 整數。

Note: Bash does not understand floating point arithmetic.

注意:Bash 不認得浮點數的算術運算。

It treats numbers containing a decimal point as strings.

它會把含有小數點的數字當成字串。

a=1.5

let "b = $a   1.3"  # Error.
                    # 出錯。
# t2.sh: let: b = 1.5   1.3: syntax error in expression
#                            表示式有語法錯誤
#                            (error token is ".5   1.3")
#                            (錯誤的 token 為 ".5   1.3")

echo "b = $b"       # b=1

Use bc in scripts that that need floating point calculations or math library functions.

可以在需要浮點數運算或數學函式庫功能的那種腳本中使用 bc 指令。

bitwise operators.

位元運算子。

The bitwise operators seldom make an appearance in shell scripts.

位元運算子在 shell 腳本中是比較少見的。

Their chief use seems to be manipulating and testing values read from ports or sockets.

它們似乎是主要用來處理或測試 ports (通訊埠) 或 sockets (通訊端) 讀回來的值。

"Bit flipping" is more relevant to compiled languages, such as C and C , which provide direct access to system hardware.

"Bit flipping" (位元翻轉) 跟編譯語言更有關,例如 C 跟 C 語言,提供直接存取系統硬體的能力。

However, see vladz's ingenious use of bitwise operators in his base64.sh (Example A-54) script.

不管怎樣,我們來欣賞一下 vladz 在他的 base64.sh (範例 A-54) 腳本裡巧妙地運用位元運算子。

bitwise operators

位元運算子。

<< bitwise left shift (multiplies by 2 for each shift position)

'<<' 位元左移 (每左移一位元等效於乘以 2)

<<= left-shift-equal

'<<=' 左移-等號

let "var <<= 2" results in var left-shifted 2 bits (multiplied by 4)

'let "var <<= 2"' 結果為 *var* 左移 2 位元 (等效於乘以 4)

>> bitwise right shift (divides by 2 for each shift position)

'>>' 位元右移 (每右移一位元等效於除以 2)

>>= right-shift-equal (inverse of <<=)

'>>=' *右移-等號* ('<<=' 的反向)

& bitwise AND

'&' 位元且

&= bitwise AND-equal

'&=' 位元且-等號

| bitwise OR

'|' 位元或

|= bitwise OR-equal

'|=' 位元或-等號

~ bitwise NOT

'~' 位元反

^ bitwise XOR

'^' 位元互斥或

^= bitwise XOR-equal

'^=' 位元互斥或-等號

logical (boolean) operators

邏輯 (布林) 運算子

! NOT

'!' 非

if [ ! -f $FILENAME ]
then
  ...

&& AND

'&&' 且

if [ $condition1 ] && [ $condition2 ]
#  Same as:  if [ $condition1 -a $condition2 ]
#  等同:if [ $condition1 -a $condition2 ]
#  Returns true if both condition1 and condition2 hold true...
#  若 condition1 和 condition2 皆為 true... 則回傳 true.

if [[ $condition1 && $condition2 ]]    # Also works.
                                       # 這樣寫也行。
#  Note that && operator not permitted inside brackets
#  of [ ... ] construct.
#  注意:那個 && 運算子並不允許寫在上述單中括號 [ ... ] 結構裡。

Note: && may also be used, depending on context, in an and list to concatenate commands.

注意:取決於內文, '&&' 也可以用在一個 and list 中,用以串接指令。

|| OR

'||' 或

if [ $condition1 ] || [ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# 等同:if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...
# 若 condition1 或 condition2 其中一個為 true... 則回傳 true.

if [[ $condition1 || $condition2 ]]    # Also works.
                                       # 這樣寫也行。
#  Note that || operator not permitted inside brackets
#  of a [ ... ] construct.
# 注意:那個 || 運算子並不允許寫在上述單中括號 [ ... ] 結構裡。

Note: Bash tests the exit status of each statement linked with a logical operator.

注意:Bash 會測試使用邏輯運算子連結起來的每個述敘指令之離開狀態。

Example 8-3. Compound Condition Tests Using && and ||

範例 8-3. 使用 && 跟 || 混合條件測試

#!/bin/bash

a=24
b=47

if [ "$a" -eq 24 ] && [ "$b" -eq 47 ]
then
  echo "Test #1 succeeds."
else
  echo "Test #1 fails."
fi

# ERROR:   if [ "$a" -eq 24 && "$b" -eq 47 ]
# 錯誤:   if [ "$a" -eq 24 && "$b" -eq 47 ]
#          attempts to execute ' [ "$a" -eq 24 '
#          企圖嘗試執行 ' [ "$a" -eq 24 '
#          and fails to finding matching ']'.
#          而且無法找到匹配的 ']'.
#
#  Note:  if [[ $a -eq 24 && $b -eq 24 ]]  works.
#  注意: if [[ $a -eq 24 && $b -eq 24 ]]  這樣寫是可以動的。
#  The double-bracket if-test is more flexible
#  than the single-bracket version.
#  雙中括號的 if-test 比單中括號的更有彈性。
#    (The "&&" has a different meaning in line 17 than in line 6.)
#    ("&&" 在第 17 行跟第 6 行 的意義是不一樣的。)
#    Thanks, Stephane Chazelas, for pointing this out.
#    感謝 Stephane Chazelas 提供這一招。


if [ "$a" -eq 98 ] || [ "$b" -eq 47 ]
then
  echo "Test #2 succeeds."
else
  echo "Test #2 fails."
fi


#  The -a and -o options provide
#  -a 與 -o 選項提供了
#  an alternative compound condition test.
#  另一種混合的條件測試。
#  Thanks to Patrick Callahan for pointing this out.
#  感謝 Patrick Callahan 提供這一招。


if [ "$a" -eq 24 -a "$b" -eq 47 ]
then
  echo "Test #3 succeeds."
else
  echo "Test #3 fails."
fi


if [ "$a" -eq 98 -o "$b" -eq 47 ]
then
  echo "Test #4 succeeds."
else
  echo "Test #4 fails."
fi


a=rhino
b=crocodile
if [ "$a" = rhino ] && [ "$b" = crocodile ]
then
  echo "Test #5 succeeds."
else
  echo "Test #5 fails."
fi

exit 0

The && and || operators also find use in an arithmetic context.

你亦可在算術運算的內容中發現 && 與 || 運算子的蹤跡。

bash$ echo $(( 1 && 2 )) $((3 && 0)) $((4 || 0)) $((0 || 0))
1 0 1 0

miscellaneous operators

其他各式各樣的運算子

, Comma operator

',' 逗號運算子

The comma operator chains together two or more arithmetic operations. All the operations are evaluated (with possible side effects. [39]

逗號運算子可串接兩個以上的算術運算。所有算術運算皆會被求值 (可能有副作用。 [39]

let "t1 = ((5   3, 7 - 1, 15 - 4))"
echo "t1 = $t1"           ^^^^^^  # t1 = 11
# Here t1 is set to the result of the last operation. Why?
# 這裡的 t1 會被設定成最後一個算術運算的求值結果。但為何如此?

let "t2 = ((a = 9, 15 / 3))"      # Set "a" and calculate "t2".
                                  # 一邊設定 "a" 一邊將計算結果賦值至 "t2"。
echo "t2 = $t2    a = $a"         # t2 = 5    a = 9

The comma operator finds use mainly in for loops. See Example 11-13.

逗號運算子主要是被用在 for loops. 詳情請參閱:範例 11-13.