о_операторах_сравнения

Краткое описание

Операторы сравнения в PowerShell могут сравнить два значения или фильтровать элементы коллекции с входным значением.

Длинное описание

Операторы сравнения позволяют сравнивать значения или находить значения, соответствующие указанным шаблонам. PowerShell включает следующие операторы сравнения:

равенство

  • -eq, -ieq, -ceq - равно
  • -ne, -ine, -cne - не равно
  • -gt, -igt, -cgt - больше
  • -ge, -ige, -cge - больше или равно
  • -lt, -ilt, -clt - меньше
  • -le, -ile, -cle - меньше или равно

Сопоставление

  • -like, -ilike, -clike — строка соответствует шаблону подстановочных знаков
  • -notlike, -inotlike, -cnotlike — строка не соответствует шаблону подстановочных знаков
  • -match, -imatch, -cmatch — строка соответствует шаблону regex
  • -notmatch, -inotmatch, -cnotmatch — строка не соответствует шаблону regex

замена

  • -replace, -ireplace-creplace находит и заменяет строки, соответствующие шаблону регулярных выражений.

Изоляция хранения

  • -contains, -icontains, -ccontains — коллекция содержит значение
  • -notcontains, -inotcontains, -cnotcontains — коллекция не содержит значения
  • -in, -iin, -cin — значение находится в коллекции
  • -notin, -inotin, -cnotin — значение не в коллекции

типа

  • -is — оба объекта являются одинаковыми типами
  • -isnot — объекты не одного типа

Общие функции

Сравнение строк не учитывает регистр, если не используется явный оператор, учитывающий регистр. Чтобы сделать оператор сравнения учитывающим регистр, добавьте c после -. Например, -ceq является чувствительной к регистру версией -eq. Чтобы явным образом указать на нечувствительность к регистру, добавьте i после -. Например, -ieq является явной регистронезависимой версией -eq.

Сравнения строк используют InvariantCulture для чувствительных и нечувствительных к регистру сравнений. Сравнения производятся между кодовыми точками Unicode и не используют порядок сортировки, зависящего от языка и региональных параметров. Результаты одинаковы независимо от текущей культуры.

Если левое значение в выражении сравнения является скалярным значением , оператор возвращает логическое значение . Если левое значение в выражении является коллекцией, оператор возвращает элементы коллекции, соответствующие правому значению выражения. Значения справа всегда рассматриваются как одноэлементные экземпляры, даже если они являются коллекциями. Операторы сравнения не могут эффективно сравнивать коллекции с коллекциями.

Если в коллекции нет совпадений, операторы сравнения возвращают пустой массив. Например:

$a = (1, 2) -eq 3
$a.GetType().Name
$a.Count
Object[]
0

Существует несколько исключений:

  • Операторы проверки содержимого и типа всегда возвращают булевое значение .
  • Оператор -replace возвращает результат замены
  • Операторы -match и -notmatch также заполняют $Matches автоматическую переменную, если левая часть выражения не является коллекцией.

Операторы равенства

-eq и -ne

Если левая сторона скалярна, -eq возвращает значение True, если правая сторона эквивалентна, в противном случае -eq возвращает значение False. -ne делает противоположное; он возвращает false, если обе стороны эквивалентны; в противном случае -ne возвращает значение True.

Пример:

2 -eq 2                 # Output: True
2 -eq 3                 # Output: False
'abc' -eq 'abc'         # Output: True
'abc' -eq 'abc', 'def'  # Output: False
'abc' -ne 'def'         # Output: True
'abc' -ne 'abc'         # Output: False
'abc' -ne 'abc', 'def'  # Output: True

Когда левая сторона является коллекцией, -eq возвращает те элементы, которые соответствуют правой стороне, а -ne фильтрует их.

Пример:

1,2,3 -eq 2             # Output: 2
'abc', 'def' -eq 'abc'  # Output: abc
'abc', 'def' -ne 'abc'  # Output: def

Эти операторы обрабатывают все элементы коллекции. Пример:

'zzz', 'def', 'zzz' -eq 'zzz'
zzz
zzz

Оператор равенства может сравнить объекты разных типов. Важно понимать, что значение в правой части сравнения можно преобразовать в тип левого значения для сравнения.

Например, строка '1.0' преобразуется в целое число для сравнения со значением 1. В этом примере возвращается True.

PS> 1 -eq '1.0'
True

В этом примере значение 1 преобразуется в строку для сравнения со строкой '1.0'. В этом примере возвращается False.

PS> '1.0' -eq 1
False

Операторы равенства принимают любые два объекта, а не только скаляр или коллекцию. Но результат сравнения не гарантируется значимым для конечного пользователя. В следующем примере показана проблема.

class MyFileInfoSet {
    [string]$File
    [int64]$Size
}
$a = [MyFileInfoSet]@{File = 'C:\Windows\explorer.exe'; Size = 4651032}
$b = [MyFileInfoSet]@{File = 'C:\Windows\explorer.exe'; Size = 4651032}
$a -eq $b
False

В этом примере мы создали два объекта с одинаковыми свойствами. Тем не менее, результат теста равенства False, так как они являются разными объектами. Чтобы создать сопоставимые классы, необходимо реализовать System.IEquatable<T> в классе. В следующем примере показана частичная реализация класса MyFileInfoSet, реализующего System.IEquatable<T> и имеет два свойства, File и Size. Метод Equals() возвращает True, если свойства File и Size двух объектов MyFileInfoSet одинаковы.

class MyFileInfoSet : System.IEquatable[Object] {
    [string]$File
    [int64]$Size

    [bool] Equals([Object] $obj) {
        return ($this.File -eq $obj.File) -and ($this.Size -eq $obj.Size)
    }
}
$a = [MyFileInfoSet]@{File = 'C:\Windows\explorer.exe'; Size = 4651032}
$b = [MyFileInfoSet]@{File = 'C:\Windows\explorer.exe'; Size = 4651032}
$a -eq $b
True

Видный пример сравнения произвольных объектов заключается в том, чтобы узнать, является ли они null. Но если необходимо определить, является ли переменная $null, необходимо поместить $null слева от оператора равенства. Помещение его на правую сторону не приведёт к ожидаемому результату.

Например, пусть $a будет массивом, содержащим нулевые элементы.

$a = 1, 2, $null, 4, $null, 6

Следующие тесты проверяют, что $a не является null.

$null -ne $a
True

Следующая функция удаляет все нулевые элементы из $a:

$a -ne $null # Output: 1, 2, 4, 6
1
2
4
6

-gt, -ge, -lt и -le

-gt, -ge, -ltи -le ведут себя очень аналогично. Если обе стороны скалярны, они возвращают True или False в зависимости от того, как две стороны сравнивают:

Оператор Возвращает значение True, когда...
-gt Левая сторона больше
-ge Левая сторона больше либо равна
-lt Левая сторона меньше
-le Левая сторона меньше или равна

В следующих примерах все выражения возвращают True.

8 -gt 6  # Output: True
8 -ge 8  # Output: True
6 -lt 8  # Output: True
8 -le 8  # Output: True

Заметка

В большинстве языков программирования оператор больше, чем >. В PowerShell этот символ используется для перенаправления. Дополнительные сведения см. в about_Redirection.

Если левая сторона является коллекцией, эти операторы сравнивают каждый член коллекции с правой стороной. В зависимости от своей логики они либо сохраняют, либо отбрасывают элемент.

Пример:

$a=5, 6, 7, 8, 9

Write-Output 'Test collection:'
$a

Write-Output "`nMembers greater than 7"
$a -gt 7

Write-Output "`nMembers greater than or equal to 7"
$a -ge 7

Write-Output "`nMembers smaller than 7"
$a -lt 7

Write-Output "`nMembers smaller than or equal to 7"
$a -le 7
Test collection:
5
6
7
8
9

Members greater than 7
8
9

Members greater than or equal to 7
7
8
9

Members smaller than 7
5
6

Members smaller than or equal to 7
5
6
7

Эти операторы работают с любым классом, реализующим System.IComparable.

Примеры:

# Date comparison
[datetime]'2001-11-12' -lt [datetime]'2020-08-01' # True

# Sorting order comparison
'a' -lt 'z'           # True; 'a' comes before 'z'
'macOS' -ilt 'MacOS'  # False
'MacOS' -ilt 'macOS'  # False
'macOS' -clt 'MacOS'  # True; 'm' comes before 'M'

В следующем примере показано, что на американской клавиатуре QWERTY нет символа, который сортируется после "a". Он передает набор, содержащий все такие символы оператору -gt, чтобы сравнить их с "a". Выходные данные являются пустым массивом.

$a=' ','`','~','!','@','#','$','%','^','&','*','(',')','_','+','-','=',
   '{','}','[',']',':',';','"','''','\','|','/','?','.','>',',','<'
$a -gt 'a'
# Output: Nothing

Если две стороны операторов не являются разумно сопоставимыми, эти операторы вызывают незавершающую ошибку.

Операторы сопоставления

Соответствующие операторы (-like, -notlike, -matchи -notmatch) находят элементы, соответствующие или не соответствуют указанному шаблону. Шаблон для -like и -notlike представляет собой подстановочное выражение (содержащее*?, и[ ]), а также -match-notmatch принимает регулярное выражение (regex).

Синтаксис:

<string[]> -like    <wildcard-expression>
<string[]> -notlike <wildcard-expression>
<string[]> -match    <regular-expression>
<string[]> -notmatch <regular-expression>

Если входные данные этих операторов являются скалярным значением, они возвращают логическое значение.

Если входные данные являются коллекцией значений, каждый элемент в коллекции преобразуется в строку для сравнения. Операторы -match и -notmatch возвращают все соответствующие и не соответствующие члены соответственно. Однако операторы -like и -notlike возвращают элементы в виде строк. Строка, возвращаемая для члена коллекции оператором -like и -notlike, является строкой, используемой для сравнения, и получается путем приведения члена к строке.

-like и -notlike

-like и -notlike ведут себя аналогично -eq и -ne, но справа может быть строка, содержащая подстановочные знаки .

Пример:

'PowerShell' -like    '*shell'           # Output: True
'PowerShell' -notlike '*shell'           # Output: False
'PowerShell' -like    'Power?hell'       # Output: True
'PowerShell' -notlike 'Power?hell'       # Output: False
'PowerShell' -like    'Power[p-w]hell'   # Output: True
'PowerShell' -notlike 'Power[p-w]hell'   # Output: False

'PowerShell', 'Server' -like '*shell'    # Output: PowerShell
'PowerShell', 'Server' -notlike '*shell' # Output: Server

Для получения наилучших -like результатов справа от оператора должен -notlike быть строковый литерал, содержащий выражение подстановочного знака. PowerShell передает выражение подстановочного знака синтаксическому анализатору. Чтобы сопоставить один из подстановочных знаков (*или?[ ]), необходимо экранировать его с помощью символа backtick (`). Например, чтобы сопоставить литерал ?, используйте `? в выражении подстановочного знака. Если вы используете расширяемое строковое выражение PowerShell, разверните строку перед передачей в средство синтаксического анализа подстановочных знаков, что приводит к отправке неисканированных символов в виде подстановочных знаков.

# Escaped literals in an expandable string
PS> "f`?`?"
f??
# Escaped literals in a literal string
PS> 'f`?`?'
f`?`?
# Comparison containing 2 wildcards
PS> 'f??' -like 'f??'
True
PS> 'for' -like 'f??'
True
# Comparison containing literal '?' characters
PS> 'f??' -like 'f`?`?'
True
PS> 'for' -like 'f`?`?'
False

-match и -notmatch

-match и -notmatch используют регулярные выражения для поиска шаблона в значениях с левой стороны. Регулярные выражения могут соответствовать сложным шаблонам, таким как адреса электронной почты, UNC-пути или отформатированные номера телефонов. Строка справа должна соответствовать правилам регулярных выражений и.

Заметка

Плохо разработанные или вредоносные регулярные выражения могут создавать условия отказа в обслуживании. Дополнительные сведения см. в разделе "Безопасность регулярных выражений " этой статьи.

Скалярные примеры:

# Partial match test, showing how differently -match and -like behave
'PowerShell' -match 'shell'        # Output: True
'PowerShell' -like  'shell'        # Output: False

# Regex syntax test
'PowerShell' -match    '^Power\w+' # Output: True
'bag'        -notmatch 'b[iou]g'   # Output: True

Если входные данные являются коллекцией, операторы возвращают соответствующие элементы этой коллекции.

Примеры коллекций:

'PowerShell', 'Super PowerShell', 'Power's hell' -match '^Power\w+'
# Output: PowerShell

'Rhell', 'Chell', 'Mel', 'Smell', 'Shell' -match 'hell'
# Output: Rhell, Chell, Shell

'Bag', 'Beg', 'Big', 'Bog', 'Bug'  -match 'b[iou]g'
#Output: Big, Bog, Bug

'Bag', 'Beg', 'Big', 'Bog', 'Bug'  -notmatch 'b[iou]g'
#Output: Bag, Beg

-match и -notmatch поддерживают группы записи регулярных выражений. Каждый раз, когда они выполняются с скалярными входными данными, и результат -matchTrue, или результат -notmatchFalse, перезаписывается $Matches автоматическая переменная. $Matches — это хеш-таблица, которая всегда имеет ключ с именем '0', который сохраняет всё совпадение. Если регулярное выражение содержит группы захвата, $Matches содержит дополнительные ключи для каждой группы.

Важно отметить, что хеш-таблица $Matches содержит только первое вхождение любого соответствующего шаблона.

Пример:

$string = 'The last logged on user was CONTOSO\jsmith'
$string -match 'was (?<domain>.+)\\(?<user>.+)'

$Matches

Write-Output "`nDomain name:"
$Matches.domain

Write-Output "`nUser name:"
$Matches.user
True

Name                           Value
----                           -----
domain                         CONTOSO
user                           jsmith
0                              was CONTOSO\jsmith

Domain name:
CONTOSO

User name:
jsmith

Если результат -matchfalseили результат -notmatchTrueили если входные данные являются коллекцией, $Matches автоматическая переменная не перезаписывается. Следовательно, он будет содержать ранее заданное значение или $null, если переменная не была задана. При ссылке на $Matches после вызова одного из этих операторов рекомендуется убедиться, что переменная была задана вызовом текущего оператора с помощью инструкции условия.

Пример:

if ('<version>1.0.0</version>' -match '<version>(.*?)</version>') {
    $Matches
}

Дополнительные сведения см. в разделе о регулярных выражениях и об автоматических переменных.

Оператор замены

Как и -match, оператор -replace использует регулярные выражения для поиска указанного шаблона. Но в отличие от -match, он заменяет совпадения другим указанным значением.

Заметка

Плохо разработанные или вредоносные регулярные выражения могут создавать условия отказа в обслуживании. Дополнительные сведения см. в разделе "Безопасность регулярных выражений " этой статьи.

Замена регулярными выражениями

Синтаксис:

<input> -replace <regular-expression>, <substitute>

Оператор заменяет все или часть значения указанным значением с помощью регулярных выражений. Оператор можно использовать для многих административных задач, таких как переименование файлов. Например, следующая команда изменяет расширения имени файла всех файлов .txt на .log:

Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }

По умолчанию оператор -replace не учитывает регистр. Чтобы сделать регистр конфиденциальным, используйте -creplace. Чтобы явным образом сделать его регистронезависимым, используйте -ireplace.

Примеры:

'book' -ireplace 'B', 'C' # Case insensitive
'book' -creplace 'B', 'C' # Case-sensitive; hence, nothing to replace
Cook
book

Начиная с PowerShell 7.2, когда левый операнд в операторе -replace не является строкой, этот операнд преобразуется в строку. PowerShell выполняет преобразование строки без учета языка и культуры.

Например, если язык и региональные параметры установлены на французский (fr), то преобразование строки с учетом культурных особенностей значения 1.2 даст 1,2.

До PowerShell 7.2:

PS> [cultureinfo]::CurrentCulture = 'fr'
PS> 1.2 -replace ','
12

В PowerShell 7.2 и более поздних версиях:

PS> [cultureinfo]::CurrentCulture = 'fr'
PS> 1.2 -replace ','
1.2

Подстановки регулярных выражений

Также можно использовать регулярные выражения для динамической замены текста с помощью групп записи и подстановок. Ссылки на группы захвата можно использовать в строке <substitute> с помощью знака доллара ($) перед идентификатором группы.

В следующем примере оператор -replace принимает имя пользователя в виде DomainName\Username и преобразуется в формат Username@DomainName:

$SearchExp = '^(?<DomainName>[\w-.]+)\\(?<Username>[\w-.]+)$'
$ReplaceExp = '${Username}@${DomainName}'

'Contoso.local\John.Doe' -replace $SearchExp, $ReplaceExp
John.Doe@Contoso.local

Предупреждение

Символ $ имеет синтаксические роли как в PowerShell, так и в регулярных выражениях:

  • В PowerShell между двойными кавычками он обозначает переменные и выступает в качестве оператора вложенных выражений.
  • В строках поиска Regex он обозначает конец строки.
  • В строках подстановки Regex он обозначает захваченные группы. Не забудьте поместить регулярные выражения между одинарными кавычками или вставить перед ними символ обратного апострофа (`).

Например:

$1 = 'Goodbye'

'Hello World' -replace '(\w+) \w+', "$1 Universe"
# Output: Goodbye Universe

'Hello World' -replace '(\w+) \w+', '$1 Universe'
# Output: Hello Universe

$$ в Regex обозначает литерал $. Это $$ в строке подстановки, чтобы включить символ $ в итоговую замену. Например:

'5.72' -replace '(.+)', '$ $1' # Output: $ 5.72
'5.72' -replace '(.+)', '$$$1' # Output: $5.72
'5.72' -replace '(.+)', '$$1'  # Output: $1

Дополнительные сведения см. в разделе о регулярных выражениях и о заменах в регулярных выражениях.

Замена в коллекции

Когда <input> оператору -replace является коллекцией, PowerShell применяет замену к каждому значению в коллекции. Например:

'B1','B2','B3','B4','B5' -replace 'B', 'a'
a1
a2
a3
a4
a5

Замена с помощью скриптблока

В PowerShell 6 и более поздних версиях -replace оператор также принимает блок скрипта, выполняющий замену. Блок скрипта выполняется один раз для каждого совпадения.

Синтаксис:

<String> -replace <regular-expression>, {<Script-block>}

В блоке скрипта используйте $_ автоматическую переменную для доступа к вводу текста, заменяемого и другими полезными сведениями. Тип класса этой переменной System.Text.RegularExpressions.Match.

Следующий пример заменяет каждую последовательность из трех цифр эквивалентами символов. Блок скрипта выполняется для каждого набора трех цифр, которые необходимо заменить.

'072101108108111' -replace '\d{3}', {return [char][int]$_.Value}
Hello

Операторы хранения

Операторы содержимого (-contains, -notcontains, -inи -notin) похожи на операторы равенства, за исключением того, что они всегда возвращают логическое значение , даже когда входные данные представляют собой коллекцию. Эти операторы перестают сравнивать, как только они обнаруживают первое совпадение, а операторы равенства оценивают все входные элементы. В очень большой коллекции эти операторы возвращаются быстрее, чем операторы равенства.

-содержит и -notcontains

Синтаксис:

<Collection> -contains <scalar-object>
<Collection> -notcontains <scalar-object>

Эти операторы сообщают, включает ли набор определенный элемент. -contains возвращает значение True, если правый (скалярный объект) соответствует одному из элементов в наборе. -notcontains вместо этого возвращает False.

Примеры:

'abc', 'def' -contains 'def'                  # Output: True
'abc', 'def' -notcontains 'def'               # Output: False
'Windows', 'PowerShell' -contains 'Shell'     # Output: False
'Windows', 'PowerShell' -notcontains 'Shell'  # Output: True
'abc', 'def', 'ghi' -contains 'abc', 'def'    # Output: False
'abc', 'def', 'ghi' -notcontains 'abc', 'def' # Output: True

Более сложные примеры:

$DomainServers = 'ContosoDC1', 'ContosoDC2', 'ContosoFileServer',
                 'ContosoDNS', 'ContosoDHCP', 'ContosoWSUS'
$thisComputer  = 'ContosoDC2'

$DomainServers -contains $thisComputer
# Output: True

Если правый операнд является коллекцией, эти операторы преобразуют значение в его строковое представление перед сравнением его с левой стороной коллекции.

$a = 'abc', 'def'
'abc', 'def', 'ghi' -contains $a # Output: False

# The following statements are equivalent
$a, 'ghi' -contains $a           # Output: True
'$a', 'ghi' -contains $a         # Output: True
'abc def', 'ghi' -contains $a    # Output: True

-in и -notin

Синтаксис:

<scalar-object> -in <Collection>
<scalar-object> -notin <Collection>

Операторы -in и -notin были представлены в PowerShell 3 в качестве синтаксической противоположности операторам -contains и -notcontains. -in возвращает значение True, если <scalar-object> слева соответствует одному из элементов коллекции. -notin вместо этого возвращает False.

В следующих примерах выполняются те же действия, что и в примерах для -contains и -notcontains, но они написаны с помощью -in и -notin.

'def' -in 'abc', 'def'                  # Output: True
'def' -notin 'abc', 'def'               # Output: False
'Shell' -in 'Windows', 'PowerShell'     # Output: False
'Shell' -notin 'Windows', 'PowerShell'  # Output: True
'abc', 'def' -in 'abc', 'def', 'ghi'    # Output: False
'abc', 'def' -notin 'abc', 'def', 'ghi' # Output: True

Более сложные примеры:

$DomainServers = 'ContosoDC1', 'ContosoDC2', 'ContosoFileServer',
                 'ContosoDNS', 'ContosoDHCP', 'ContosoWSUS'
$thisComputer  = 'ContosoDC2'

$thisComputer -in $DomainServers
# Output: True

Если левый операнд является коллекцией, эти операторы преобразуют значение в его строковое представление перед сравнением его с правой коллекцией.

$a = 'abc', 'def'
$a -in 'abc', 'def', 'ghi' # Output: False

# The following statements are equivalent
$a -in $a, 'ghi'           # Output: True
$a -in '$a', 'ghi'         # Output: True
$a -in 'abc def', 'ghi'    # Output: True

Сравнение типов

Операторы сравнения типов (-is и -isnot) используются для определения того, является ли объект конкретным типом.

Синтаксис:

<object> -is <type-reference>
<object> -isnot <type-reference>

Пример:

$a = 1
$b = '1'
$a -is [int]           # Output: True
$a -is $b.GetType()    # Output: False
$b -isnot [int]        # Output: True
$a -isnot $b.GetType() # Output: True

Безопасность регулярных выражений

Количество операций сравнения, необходимых для сопоставления шаблона регулярного выражения, может увеличиться экспоненциально, если шаблон включает большое количество конструкций изменения, испециально, если он включает вложенные необязательные квантификаторы. Например, шаблон ^(a+)+$ регулярного выражения предназначен для сопоставления полной строки, содержащей один или несколько символов a. Обработчик регулярных выражений должен использовать регулярное выражение для выполнения всех возможных путей через данные, прежде чем он сможет заключить, что совпадение неудачно, а вложенные скобки создают множество дополнительных путей через данные.

Предупреждение

Злоумышленник может предоставлять входные данные регулярным выражениям, вызывая атаку типа "отказ в обслуживании", также называемую атакой ReDoS.

Чтобы защититься от сценариев ReDoS, создайте [regex] объекты, которые указывают время ожидания. Обработчик регулярных выражений завершает поиск совпадения при превышении предельного времени. Например, следующий код создает объект regex с 2-секундным тайм-аутом:

$pattern = '^(a+)+$'
$regexOptions = 'None'
$matchTimeout = [timespan]::FromSeconds(2)
$regex = [regex]::new($pattern, $regexOptions, $matchTimeout)
$regex.IsMatch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX')

Через 2 секунды обработчик regex завершает поиск и возвращает следующую ошибку:

MethodInvocationException: Exception calling "IsMatch" with "1" argument(s):
"The Regex engine has timed out while trying to match a pattern to an input
string. This can occur for many reasons, including very large inputs or
excessive backtracking caused by nested quantifiers, back-references and other
factors."

Дополнительные сведения о [regex] производительности класса и regex см. в следующих статьях:

См. также