Я использую powershell или cmd, чтобы открыть текстовый файл и получить внутри определенное значение или текст.
В настоящее время вывод внутри текстового файла выглядит следующим образом:
Upload Hello.zip: 0 of 933 bytes complete
Upload Hello.zip: 933 of 933 bytes complete
{
"scanId" : 11260434,
"scanType" : "Static",
"analysisStatusType" : "Pending",
"applicationName" : "Test Application Jenkins",
"releaseName" : "Release 4",
"microserviceName" : "",
"__action__" : "STARTED"
}
Однако я хотел бы получить значение только из идентификатора сканирования.
Это команда, которую я использую:
Select-String -Path C:\Folder\scanjson.txt ':\s*(?<digits>[0-9]+)'
Но он вернет вывод следующим образом:
C:\Folder\scanjson.txt:2:Upload Hello.zip: 0 of 933 bytes complete
C:\Folder\scanjson.txt:4:Upload Hello.zip: 933 of 933 bytes complete
C:\Folder\scanjson.txt:6: "scanId" : 11260434,
Поскольку ваш текстовый файл в основном состоит из JSON, лучше и надежнее удалить преамбулу, отличную от JSON, и использовать ConvertFrom-Json для анализа JSON в объект, к свойствам которого вы можете получить доступ для получения желаемой информации:
# -> 11260434, i.e. a *number*, due to from-JSON parsing.
(
(Get-Content -Raw C:\Folder\scanjson.txt) -replace '(?s)^.+(?=\{)' |
ConvertFrom-Json
).scanId
Get-Content-Raw
считывает файл целиком в одну многострочную строку.
-replace '(?s)^.+(?=\{)'
удаляет все до первого символа {
, исключая его; компоненты регулярного выражения следующие:
(?s)
— это встроенная опция, которая заставляет .
соответствовать символам новой строки.^
соответствует началу строки..+
соответствует любой непустой (+
) серии символов (.
); если ваш входной файл не всегда имеет преамбулу, используйте вместо нее .*
.(?=\{)
— это предварительное утверждение, которое соответствует символу {
, не включая его в сопоставление.Полученная строка представляет собой действительный JSON, который ConvertFrom-Json анализирует экземпляры [pscustomobject], к свойствам которых, например .scanId
, вы можете получить доступ.
11260434
, анализируется как число.[int]
(System.Int32
) в Windows PowerShell, а не как [long]
(System.Int64
) в PowerShell (Core) 7.Что касается того, что вы пробовали:
Ваше регулярное выражение было слишком либеральным; использовать"scanId"\s*:\s*(?<digits>[0-9]+)
вместо этого;[1] т. е.:
# -> '11260434', i.e. a *string*, due to regex parsing.
(
Select-String -List -Path C:\Folder\scanjson.txt '"scanId"\s*:\s*(?<digits>[0-9]+)'
).Matches[0].Groups['digits'].Value
Обратите внимание, что необходимо детализировать выходной объект Select-String , который имеет тип [Microsoft.PowerShell.Commands.MatchInfo], чтобы получить интересующее значение группы захвата.
-List
гарантирует, что сопоставление прекратится после первого совпадения.
Примечание. В случаях, когда вы ожидаете несколько совпадений, вы должны опустить -List
и передать вызов ForEach-Object вместо использования прямого доступа к свойству результата (как показано выше):
Select-String -Path C:\Folder\scanjson.txt '"scanId"\s*:\s*(?<digits>[0-9]+)'|
ForEach-Object { $_.Matches[0].Groups['digits'].Value }
Из-за использования синтаксического анализа на основе регулярных выражений результатом является строка, просто приведите все выражение к, например [int]
чтобы получить номер.
[1] For an explanation of the regex and the option to experiment with it, see this regex101.com page . Note that regex101.com's .NET support is limited to C#, which may require tweaks to PowerShell regexes, such as not using '...'
and escaping "
chars. as ""
; see this answer for guidance.
Спасибо! Основной комментарий/ответ сработал для меня. Что касается того, что я пробовал, я тестировал его на этом сайте: regex101.com/r/IgaNue/1
Рад это слышать, @Джордж; решение Select-String
тоже должно работать, хотя оно возвращает строку (которую можно легко привести к [int]
). Напротив, решение ConvertFrom-Json
возвращает число (типа [int]
в Windows PowerShell и [long]
в PowerShell (Core) 7)
Я использовал это раньше: Select-String -Path C:\Folder\scanjson.txt '"scanId":\s*(?<digits>[0-9]+)' -List | ForEach-Object { $_.Matches[0].Groups['digits'].Value }
@Джордж: В принципе это работает, но регулярное выражение нарушено; это работает: Select-String -Path C:\Folder\scanjson.txt '"scanId"\s*:\s*(?<digits>[0-9]+)' -List | ForEach-Object { $_.Matches[0].Groups['digits'].Value }
. Поскольку ожидается только один результат, мое решение обходится без вызова ForEach-Object
.
@Джордж, повтори ссылку на regex101.com: у тебя были синтаксические ошибки, поскольку сайт требует синтаксиса C#; пожалуйста, см. только что добавленную сноску, в которой есть ссылка с исправленной попыткой и ссылка на ответ, в котором объясняется, как обычно тестировать регулярные выражения PowerShell на regex101.com.
Плохо, я могу подтвердить, что метод Select-String тоже теперь работает. Я также мог бы попробовать эту команду напрямую, без необходимости сохранять данные в текстовый файл. еще раз спасибо!
Попробуйте
"scanId"\s*:\s*(?<digits>[0-9]+)
?