Windows PowerShell講座(6)—運算子(上)

發佈日期: 2008 年 4 月 21 日

**作者:**賴榮樞
    www.goodman-lai.idv.tw

Windows PowerShell 提供了豐富的運算子讓我們處理程式裡的各種運算,我們將分兩篇文章來說明,本文將先說明其中的算術運算、指定運算、比較運算。

本頁內容

運算式、運算子、運算元
算術運算
指定運算
比較運算
結語

程式的執行過程充滿了許許多多的運算,在程式裡,我們會將運算的過程寫成運算式,而程式執行運算式便能完成運算。

運算式、運算子、運算元

運算式是由運算元和運算子所構成,運算子是運算式裡參與運算的符號(例如算術運算的 +、-、*、/ ),而運算元則是參與運算的資料,這些資料可以直接以數值表示,也可以是變數、常數、或另一個運算式,有些程式語言甚至允許物件或函式作為運算元。

此外,根據運算子所作用的運算元數量,運算子又可分成一元運算子、二元運算子、三元運算子;例如加法運算需要兩個運算元,因此加法運算子即為二元運算子。

算術運算

Windows PowerShell 提供的算術運算子包括了加減乘除四則運算、餘數運算、負號,以及遞增和遞減運算。這些運算子列表如下。

運算子

說明

簡例

+

123 + 456

-

456 - 123

*

123 * 456

/

456 / 123

%

取餘數

456 % 123

-

負號(一元運算子)

-456

++

遞增(一元運算子)

$var = 10
$var++

--

遞減(一元運算子)

$var = 10
$var--

加、減、乘、除、餘數運算、負號應該已為一般人熟悉,於此不再贅述,但要提醒您的是,加法運算子亦可作為字串連接之用(例如 "ab" + "cd" 的結果是 abcd);此外,也應留意參與運算的運算元型別是否一致,以及 Windows PowerShell 會不會逕自對運算元轉換型別。

而關於算術運算子的優先順序,也與您認知的先乘除、後加減相同:負號最高,乘、除、取餘數其次,加、減最低。

遞增和遞減運算可能是一般人較為陌生,但如果您學過 C 語言或其家族成員的任何一種語言,對遞增和遞減應該就不至於陌生。遞增和遞減運算每次會讓運算元加 1 或減 1,它們除了是一元運算子(也就是運算時只能有一個運算元),而且只能使用於變數或屬性。Windows PowerShell 的遞增和遞減運算子也同 C 語言,可以前置、也可以後置,例如以下簡單的範例:

# 只能對變數或屬性作用,因此會導致錯誤
PS > 9++

# 先宣告變數 $var,並指定其值為 10
PS > $var = 10
# 後置遞增,遞增符號放在運算元之後
PS > $var++
# 前置遞增,遞增符號放在運算元之前
PS > ++$var
# 上述不論前置或後置,其寫法都等同於 $var = $var + 1
# 如果是遞減,等同於 $var = $var - 1
# 經過兩次的遞增運算之後,$var 的值會是 12
# 如果是兩次遞減,$var 的值會是 8
            

上述簡單例子的前置或後置應該不難理解,但如果又搭配其他的算術運算,結果可能會出乎意料,而這應該就是遞增和遞減運算最容易迷惑初接觸者的「特性」,例如以下簡單的範例:

PS > $a = 10
PS > $a++ - 3   # 結果為 7,$a 的值為 11
PS > ++$a - 3   # 結果為 9,$a 的值為 12

PS > $b = 10
PS > $b-- - 3   # 結果為 7,$a 的值為 9
PS > --$b - 3   # 結果為 5,$a 的值為 8
            

各位應該都能理解這個例子 $a 或 $b 的值:每次就是加 1 或減 1,但是對運算結果可能有疑惑。其實關鍵就在遞增和遞減運算子前置或後置的差異:如果是後置,會先進行運算式裡其他的運算(也就是 10 會先減 3),再做遞增或遞減運算;但如果是前置,則會先做遞增或遞減運算(也就是 11 先加 1、9 先減 1),接著才會進行運算式裡其他的運算(因此變成 12 - 3 以及 8 - 3 )。

指定運算

指定運算子都是二元運算,可以將運算子右側的值、物件、或另一個運算式的結果,指定給運算子左側的變數、屬性、或物件。我們之前就已經使用過的等號 (=),是最常見的指定運算子。但是除了等號之外,Windows PowerShell 還提供了另外五種具有算術運算能力的指定運算子。這些運算子列表如下。

運算子

說明

簡例

=

將運算子右側的值,指定給運算子左側的變數。

$var = 3

+=

將運算子左側的變數值,加上運算子右側的值,再指定給運算子左側的變數。

$var += 5(寫法等同於 $var = $var + 5)

-=

將運算子左側的變數值,減去運算子右側的值,再指定給運算子左側的變數。

$var -= 5(寫法等同於 $var = $var - 5)

*=

將運算子左側的變數值,乘以運算子右側的值,再指定給運算子左側的變數。

$var *= 5(寫法等同於 $var = $var * 5)

/=

將運算子左側的變數值,除以運算子右側的值,再指定給運算子左側的變數。

$var /= 5(寫法等同於 $var = $var / 5)

%=

將運算子左側的變數值,除以運算子右側的值,並取餘數,再指定給運算子左側的變數。

$var %= 5(寫法等同於 $var = $var % 5)

指定運算最需要注意的,是指定運算子左右兩側的資料型別是否對等,以及左側的變數能不能容納右側的值,例如應該要避免將字串資料指定到整數型別的變數,或者要避免將小數值放進整數型別變數;前者可能會造成錯誤,也可能會因型別自動轉換而導致意料外的結果,而後者會導致部分的資料損毀(例如將 3.14 指定到整數型別變數,變數裡的值會只剩下整數 3)

Windows PowerShell 的指定運算還有一些有趣且需要留意的地方。

16 進位值。我們可以將 16 進位值指定給變數,但是 Windows PowerShell 會先將值轉換成十進位,再將值以整數型別指定給變數:

# 16 進位的表示是以 0x(前者為數字零)作為前置
PS > $var = 0x10
PS > $var
16
            

科學記號。我們能以科學記號的表示法將數值指定給變數,但是 Windows PowerShell 換先還原,再將數值指定給變數:

PS > $var = 4.3456e3
PS > $var
4345.6
            

KB、MB、GB。慣用的 KB、MB、GB 等位元組計量方式,也可以用在指定運算,但是 Windows PowerShell 在將數值指定到變數之前,會先將值轉換成以位元組為計量的方式(K = 1024、M = 1024 * 1024、G = 1024 ^ 3):

PS > $var = 10mb   # 小寫的 mb 亦可
PS > $var
10485760     # 10 * 1024 * 1024

PS > $var = 0.3kb
PS > $var
307.2    # 0.3 * 1024
            

一行多個指定運算。只要以逗號隔開,Windows PowerShell 允許在一行程式碼執行多個指定運算,例如以下簡單的範例:

# 變數和數值的數量一樣多,相當於:
# $i = 1; $j = 2; $k = 3
PS > $a, $b, $c = 1, 2, 3

# 變數的數量多過數值,相當於:
# $a = 1; $b = 2; $c = 3, 4, 5
PS > $a, $b, $c = 1, 2, 3, 4, 5

# 承上例 $c = 3, 4, 5
# 故而 $x =3、$y = 4、$z = 5
PS > $x, $y, $z = $c

# 數值的數量多過變數,相當於:
# $n = 1; $o = 2; $p
# $p 沒有指定值,因此為 Null
PS > $n, $o, $p = 1, 2

# 一次將同一值指定給數個變數
PS > $d = $e = $f = 3
            

關於變數的指定運算,可以參考這個系列文章的《 Windows PowerShell 講座 (4)— 變數(https://www.microsoft.com/taiwan/technet/columns/profwin/66-Winpowerwshell4.mspx)》,這篇文章討論了許多指定運算之後的資料型別轉換例子,以及指定變數值的 Set-Variable。

比較運算

比較運算的結果會得到真(True)或偽(False),因此經常用在需要決策的陳述式,例如 if 或 while。但是與一般程式語言不同的是,Windows PowerShell 的比較運算子並非常見的代數比較符號,而是英文字的縮寫,因為 > 或 < 之類的符號已經用在輸出重導。這些運算子列表如下。

運算子

說明

簡例

結果

-le
-cle
-ile

小於或等於

10 -le 10
"ABC" -le "abc"
"ABC" -cle "abc"
"ABC" -ile "abc"

True
True
False
True

-like
-clike
-ilike

相似(以萬用字元比較)

"One" -like "o*"
"o*" -like "One"
"One" -clike "o*"
"One" -ilike "o*"

True
False
False
True

-notlike
-cnotlike
-inotlike

不相似(以萬用字元比較)

"One" -notlike "o*"
"o*" -notlike "One"
"One" -cnotlike "o*"
"One" -inotlike "o*"

False
True
True
False

-match
-cmatch
-imatch

符合(以規則運算式比較)

"book" -match "[iou]"
"book" -cmatch "[iou]"
"book" -imatch "[iou]"

True
True
True

-notmatch
-cnotmatch
-inotmatch

不相符(以規則運算式比較)

"book" -notmatch "[iou]"
"book" -cnotmatch "[iou]"
"book" -inotmatch "[iou]"

False
False
False

-contains
-ccontains
-icontains

包含(運算子左邊含有右邊的值)

"n", "o", "e" -contains "O"
"n", "o", "e" -ccontains "O"
"n", "o", "e" -icontains "O"

True
False
True

-notcontains
-cnotcontains
-inotcontains

不包含(運算子左邊沒有右邊的值)

"n", "o", "e" -notcontains "O"
"n", "o", "e" -cnotcontains "O"
"n", "o", "e" -inotcontains "O"

False
True
False

乍看以上表格,您可能會覺得 Windows PowerShell 的比較運算怎麼這麼複雜!運算子這麼多?這是因為 Windows PowerShell 的比較運算除了可以比較數值大小,也可以比較字串,而為了要能處理字母大小寫以及忽略大小寫的字串比較,每個比較運算子又衍生出 c 開頭和 i 開頭的運算子。

例如等於運算子 -eq 用在字串比較時,其實就是忽略大小寫的,但 Windows PowerShell 也另外提供了明確表示忽略大小寫的等於運算子 -ieq;也就是說 -eq 和 -ieq 在比較字串時,都會忽略字母大小寫,例如會將 ABC 和 abc 視為相同。但如果想要比較大小寫的差異,就要使用 c 開頭的比較運算子,例如用 -ceq 來比較 ABC 和 abc,就會因為視為不同的字串而得到 False。

比較運算的型別轉換

使用 Windows PowerShell 的比較運算應該留意運算子左右的型別是否一致,不然就應該自行加入型別轉換,或者瞭解 Windows PowerShell 自動轉換的規則,否則可能得到出乎意料的結果。

若比較運算子兩邊的運算元都是數值,則會根據寬度較大的運算元來擴大另一個運算元的數值寬度,例如一邊是整數、一邊是浮點數,就會先將整數擴大成浮點數,再行比較。將整數擴大成浮點數會加上小數點,並且將小數位數補 0,因此 678 -lt 678.9,其實是 678.0 -lt 678.9(雖然結果相同)。

如果比較運算子兩邊運算元的型別不同,會先依據左邊運算元的型別來轉換右邊運算元的型別,再進行比較運算。例如以下簡單的範例:

# 數值比較,因此會忽略 0
PS > 09 -eq 009
True

# 比較運算子兩邊運算元的型別不同,
# 因此會先依據左邊運算元的型別來轉換右邊運算元的型別,再進行比較運算,
# 故而等同於 09 -eq 009
PS > 09 -eq "009"
True

# 同上,先依據左邊運算元的型別來轉換右邊運算元的型別再進行比較運算,
# 因此等同於\\"09\\" -eq \\"009\\"
PS > "09" -eq 009
False

# 比較運算亦可自行型別轉換,
# 轉換之後等同於 09 -eq 009
PS > [int] "09" -eq 009
			

比較運算亦可自行加入型別轉換,例如以下簡單的範例:

# 左邊的運算元先轉換成整數型別
# 根據左邊運算元的型別轉換右邊運算元的型別,
# 因此會將 678.4 四捨五入變成 678
# 故而等同於 678 -lt 678
PS > [int] "678" -lt "678.4"
False

# 同上,但 678.9 會進位成 679
# 故而等同於678 -lt 679
PS > [int] "678" -lt "678.9"
True

# 左邊的運算元先轉換成倍精度浮點數型別
# 根據左邊運算元的型別轉換右邊運算元的型別,
# 故而等同於678.0 -lt 678.4
PS > [double] "678" -lt "678.4"
True

# 將字串轉換成日期型別再比較
PS > [datetime] "1/1/2007" -gt [datetime] "1/1/2006"
True
			

陣列或集合的比較運算

Windows PowerShell 的陣列或集合也可以進行比較運算,其運算結果會傳回相符的值,例如以下簡單的範例:

# 左運算元是陣列,此運算會以右運算元搜尋比較此陣列內容,
# 並找出「等於」右運算元的值;
# 結果共有兩個相等,因此列出兩個2。
PS > 2, 3, 4, 2, 3, 4 -eq 2
2
2

# 以右運算元搜尋比較此陣列內容,並找出「不等於」右運算元的值;
# 結果共有四個不相等,因此列出 1、3、4、5。
PS > 1, 2, 3, 4 -ne 2
1
3
4
5

# 以右運算元搜尋比較此陣列內容,並找出等於右運算元的值
# 比較時若兩邊的型別不同,就會根據之前所提:
# 「先依據左邊運算元的型別來轉換右邊運算元的型別,再進行比較運算」
PS > 1, "3", 5, 3 -eq "3"
3
3

# 之所以只有一個 3,是因為 \\"03\\" 並不等於 \\"3\\"
PS > 1, "03", 5, 3 -eq 3
3

# 以下是上例的小變化,請注意右運算元改成 \\"03\\",結果也不相同
PS > 1, "03", 5, 3 -eq "03"
03
3
			

上述的比較運算不只能用在等於和不等於,例如以下使用小於的例子,會以右運算元搜尋比較左邊陣列內容,並找出「小於」右運算元的值,因此結果只有 1。

PS > 1, "03", 5, 3 -lt "03"
1
			

-contains 和 -notcontains:陣列或集合的包含運算

陣列或集合的包含運算很類似上述的比較運算,但執行結果是 True 或 False,例如以下簡單的範例:

PS > 1, "03", 5, 3 -contains "03"
True

PS > "a", "b", "c", "d" -ccontains "A"
False
			

-like 和 -notlike:利用萬用字元進行相似比較

相似比較的 -like 和 -notlike 運算子可以利用萬用字元進行範圍更大的比對,比對的方式是左運算元裡是不是有右運算元?例如我們想要知道某個字串裡沒有 good 開頭的字,就可以將某個字串放在左運算元,而將「比對範式」當作右運算元。同樣的,若是要進行字母大小寫符合的比對,要改用 c 開頭的 -clike 或 -cnotlike。以下是四種萬用字元的相似比較說明。

星號(*):可用來比對任何及任何數量的字元。例如 xy*,只要是 xy 開頭皆能符合,包括 xyz、xyw、xyx 等,但如果是 bao 或 cba 就不符合。例如以下簡單的範例:

PS > "Goodman" -like "good*"
True

# -clike,大小寫需符合
PS > "Goodman" -clike "good*"
False

PS > "Goodman" -like "god*"
False

PS > "192.168.1.1" -like "192.168.1.*"
True

# 相似比較亦可用在陣列或集合,結果會傳回相符的元素
# 您可試著將 -like 改成 -notlike,並觀察運算結果
PS > "goodman", "guy", "goto", "good" -like "goo*"
goodman
good
			

問號(?):可用來比對任何的單一字元。例如 x?z,只要是 x 開頭、z 結尾的都符合,例如 xyz、xaz、xgz,但如果是 xz 就不符合。例如以下簡單的範例:

PS > "goodman" -like "goodm?n"
True

PS > "192.168.1.1" -like "192.16?.1.*"
True
			

字元範圍([字元-字元]):類似問號萬用字元,但可更精確的指定字元的範圍,例如 x[i-k]z,是指 x 開頭、z 結尾,且中間的字元是 i 到 k 的任一字元,因此只有 xiz、xjz、xkz 等三者符合。

PS > "xkz" -like "x[i-k]z"
True

PS > "goodman" -like "g[n-p]odm[a-c]n"
True
			

特定字元([字元…]):類似字元範圍,但更精確的指定可能的字元,例如 x[iw]z,是指 x 開頭、z 結尾,且中間的字元是 i 或 w,因此只有 xiz、xwz 符合。

PS > "xiz" -like "x[iw]z"
True

# 第二個字元是[a-cpmo],
# 也就是第二個字元只要是 a 到 c 任一字元或 p 或 m 或 o 皆可。
PS > "goodman" -like "g[a-cpmo]odman"
True
			

-match 和 -notmatch:比對部分內容

如果希望能更彈性的比對出部分內容,可以改用 -match 或 -notmatch 運算子,因為這些運算子支援規則運算式。例如想要找出某個字串變數裡有沒有 man 這個字,如果要找出的是 man 位於字尾的情況,可以利用前述的 -like 及星號萬用字元:

PS > $var -like "*man"

但如果要找出的是 man 可以位於字串裡的任何位置,則可以改用 -match:

PS > $var -match "man"

-match 也可以搭配一些符號來達到更便利的部分比對,例如:

  • ^:表示開頭字元。

PS > "goodman" -match "^go" True

  • $:表示結尾字元。

PS > "goodman" -match "man$" True

此外,前述 -like 用來表示字元範圍的方式,也能用在 -match,例如以下簡單的範例:

PS > "hat" -match "h[ao]t"
True

PS > "hot" -match "h[ao]t"
True

PS > "h3t" -match "h[1-5]t"
True

PS > "h9t" -match "h[1-5]t"
False
			

結語

本文介紹了 Windows PowerShell 的算術運算、指定運算、比較運算。算術運算應該最為一般人熟悉,指定運算應該是程式裡最常見,而比較運算的多樣,可能超過初次接觸者的想像。

不過 Windows PowerShell 的比較運算子雖然多樣,但依然很有條理:

  • 比較大、小、或相等與否:-eq / -ne、-gt / -ge、-lt / -le。

  • 比較相似或包含與否:-like / -notlike、-match / -notmatch、-contains / -notcantains。

而每種比較運算子又再根據字元的大小寫相同與否,延伸出 c 開頭和 i 開頭的運算子:

  • 原型(例如 -eq):大小寫視為相同。

  • c開頭(例如 -ceq):大小寫視為不同。

  • i開頭(例如 -ieq):大小寫視為相同。

由於Windows PowerShell 所提供的運算子相當豐富,為了不讓文章的篇幅太大而影響閱讀的學習效率,我們將於下一篇文章介紹其他的運算子。