В сценарии PowerShell я хотел бы проверить, существует ли уже локальная ветка, что я сейчас делаю как $existsInLocal = (git branch | sls $branch) -ne $null
, но это неверно, потому что sls $branch
соответствует строке(ям), содержащей $branch
в качестве подстроки, но мне нужна версия sls $branch
, который выводит строки, точно соответствующие $branch
.
Есть ли способ использовать ^
и $
для обозначения начала и конца строки соответственно? Мои попытки сделать это не увенчались успехом.
Я просмотрел документацию Select-String и не нашел решения.
Здесь также есть почти решение , в котором используется \b
, который соответствует границе слова, но в моем случае это не работает, поскольку имена ветвей могут содержать символы \W
(например, /
или -
). Например, \bjose/feature\b
будет соответствовать dev/jose/feature
(первый \b
соответствует переходу от /
к j
) или jose/feature/v2
или dev/jose/feature/v2
.
Я знаю есть другой способ проверить существование локальной ветки, но меня больше всего интересуют sls
точные совпадения в целом, и вариант использования «определить, существует ли локальная ветка» — лишь один из многих.
echo there | select-string ^there$
@mclayton, спасибо, ^
и $
действительно работают с sls
/select-string
. Моя проблема заключалась в том, что я не учитывал пробелы, которые git branch
печатаются перед каждым названием ветки. У меня сработало следующее git branch | sls ^\s*dev/jose$
из командной строки и в .ps1
скрипте.
Для меня @iRon использование -SimpleMatch
вернуло больше, чем просто точные совпадения; он также вернул совпадения подстроки.
@mclayton git branch --contains dev/jose
выводит `dev/jose\n *master`, если я нахожусь в ветке master
; * dev/jose\n master
если я в dev/jose
филиале; и `dev/jose\n master`, если я из любой другой ветки. Переменный вывод делает его неподходящим для сценариев. И git branch --contains dev/jos
и git branch --contains dev/josev
каждый выводит error: malformed object name dev/jos
и error: ... dev/josev
соответственно.
Таким образом, строка выбора может соответствовать точному шаблону, вам просто нужно включить начальные пробелы.
Переписывание регулярного выражения может оказаться всем, что вам нужно. Следующее работает для случайной строки с косыми чертами и тире (спасибо mklement0 за указание на упрощение).
^[-/\w]+$
Некоторые объяснения:
[]+
определяет список совпадающих символов, который может повторяться один или несколько раз/
соответствует косой черте-
соответствует тире\w
соответствует символам слова (вы это уже нашли)^
и $
будут соответствовать началу и концу строки (опять же, вы уже это выяснили)Таким образом, внутренний захват в списке будет соответствовать любому словесному символу, косой черте или тире. Если вы повторите это один или несколько раз и включите начало и конец строки, это будет соответствовать описанному вами шаблону.
Спасибо за объяснение @mklement0. Я обновил свой ответ, чтобы показать вашу строку регулярного выражения на случай, если кто-то найдет этот вопрос в будущем.
Чтобы ответить на ваш общий вопрос:
Меня действительно больше всего интересует, находит ли
sls
(Select-String
) точные совпадения в целом.
Select-String по дизайну ищет заданный поисковый запрос в виде подстроки в каждой входной строке (строке).[1]
-CaseSensitive
.По умолчанию каждый поисковый запрос, передаваемый в параметр -Pattern
(возможно, позиционно, как первый безымянный аргумент), интерпретируется как регулярное выражение (регулярное выражение).
-SimpleMatch
.Нет возможности запросить совпадение всей строки, поэтому единственный способ добиться соответствия всей строки — это использовать регулярное выражение с привязками ^
и $
.
Однако для этого может потребоваться экранирование поискового термина, предназначенного для буквального использования, чтобы любые символы, являющиеся метасимволами регулярного выражения, не были случайно интерпретированы как таковые.
Используйте [regex]::Escape(), чтобы выполнить это экранирование программно; в буквальном поисковом запросе вы можете альтернативно \
-экранировать метасимволы по отдельности.
По умолчанию Select-String
ищет все совпадения во входном файле/среди входных строк.
Чтобы он сообщал только о первом совпадении и прекратил поиск дополнительных, добавьте переключатель -List
, но учтите, что это работает только с вводом файла (либо через -Path
/-LiteralPath
, либо путем передачи объектов информации о файле через Get-ChildItem
или Get-Item
).
Чтобы он сообщал только логическое значение ($true
или $false
) в зависимости от того, было ли найдено хотя бы одно совпадение (что также прекращает поиск после первого совпадения), вместо этого добавьте переключатель -Quiet
.
Select-String
и совпадении не найдено, начиная с PowerShell 7.4.x, вместо $false
неожиданно отсутствует вывод; это следует считать ошибкой — см. выпуск GitHub № 16681.if
эквивалентен $false
, поэтому эта ошибка обычно не имеет значения.Кроме того, независимо от -List
, переключатель -AllMatches
требует, чтобы поисковый запрос сопоставлялся так часто, как он встречается в каждой строке (входной строке), а не сообщал только о первом совпадении.
Применительно к вашему случаю:
$existsInLocal = git branch | sls -Quiet ('^\s*{0}$' -f [regex]::Escape($branch))
Вышеприведенное демонстрирует технику экранирования, хотя в вашем случае это, вероятно, не обязательно, и, согласно вашему отзыву, соответствует \s*
, то есть необязательным пробелам перед именем ветки.
-Quiet
делает Select-String
вывод $true
, если совпадение было найдено (см. выше), а также прекращает поиск в этом случае - это устраняет необходимость в вашем (...) -ne $null
тесте, который, кстати, обычно лучше записать как $null -ne (...)
- см. соответствующее правило PSScriptAnalzyer
Делаем шаг назад:
Как отмечает Маклейтон , возможно более простое решение для буквального сопоставления целых строк с использованием оператора -contains:
$existsInLocal = (git branch) -contains $branch
PowerShell автоматически передает выходные данные стандартной программы внешней программы построчно и, заключая вызов в (...)
и используя его с оператором, строки собираются в массив (при условии наличия двух или более строк вывода).
-contains
затем выполняет поэлементное сравнение на равенство в этом массиве (по сути, -eq
операции с каждым элементом массива в качестве LHS) до тех пор, пока не будет найдено совпадение (не более одного), и в этом случае возвращается $true
(в противном случае $false
). В данном случае это означает буквальное сравнение целых строк.
-contains
по умолчанию тоже нечувствителен к регистру, но вы можете использовать вариант оператора с учетом регистра -ccontains
.Единственным потенциальным недостатком этого подхода является то, что он требует сбора всех строк стандартного вывода в памяти заранее, прежде чем будет выполнено сопоставление, тогда как потоковая природа конвейерного решения на основе Select-String
позволяет остановиться, как только будет найдено совпадение.
Однако при ограниченном объеме вывода стандартного вывода, как в данном случае, это не будет проблемой.
[1] The typical use case is that Select-String
receives text line by line, such as by making it search a file using -Path
/ -LiteralPath
or when piping the output of an external program to it.
However, when you pass a multiline string as a single object to it (e.g. by piping Get-Content -Raw
to it), that string is searched through as a whole, enabling cross-line matching.
У меня это работает…
$stdout = @( "main", "feature", "feature/abc", "feature/xyz" ); $stdout | select-string "^feature`$"
— обратите внимание, что вам нужно экранировать$
в шаблоне ветки. Если у вас есть конкретный контрпример, который не работает, было бы полезно включить его в свой пост. (Кроме того, если вы просто ищете точную литеральную строку без шаблонов регулярных выражений, кроме^…$
, вы можете использовать-contains
вместоselect-string
)