Разделить строки из вывода команды в Powershell

Я работаю с Perforce, и после распаковки у меня часто возникает много локальных изменений, которые я хочу удалить. Используя PowerShell, я могу распечатать файлы, которые хочу удалить, но выходная строка все еще содержит подстроки, которые я хотел бы удалить.

Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object {p4 have $_.FullName}

Это приведет к выводу файлов, которые у меня есть только локально, как «C:\Unreal\Project\File.uasset — файлы не на клиенте». и другие как "//Project/Content/File.uasset#12 - C:\Unreal\Project\File.uasset"

Файлы, которых у меня нет на клиенте, на котором я хочу удалить элементы, а другой запускается p4 sync, но в настоящее время я застрял, даже когда Write-Host выводит либо только локальный путь.

Я пробовал фильтровать выходные данные с помощью Select-String, чтобы затем попытаться вывести только такие пути, как

Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object {p4 have $_.FullName} | Select-String " not on client." | Write-Host ($_ -split ' - file(s)')[0]

Полная строка «C:\Unreal\Project\File.uasset — файлы не на клиенте». все еще печатается

Также предпринята попытка фильтрации внутри цикла следующим образом.

Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object { if ((p4 have $_.FullName) -like "*not on client." { Write-Host ($_ -split ' - file(s)')[0] } }

И снова полная строка выводится на терминал.

Я пробовал вариант разделения, например $_.Split(' - file(s)', 2)[0], но все равно печатается полная строка. И просто чтобы убедиться, я пробовал разные индексы, если бы разделение имело полную строку в качестве первого индекса, а затем имело бы результаты разделения.

Пример нефильтрованного вывода

> Get-ChildItem -Recurse -Include ("*.uasset", "*.umap") -Attributes !ReadOnly "C:\Unreal\Project\Content" | ForEach-Object {p4 have $_.FullName}
C:\Unreal\Project\Content\Example_01.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_02.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_03.uasset - file(s) not on client.
//Project/Content/Example_04.uasset#11 - C:\Unreal\Project\Content\Example_04.uasset
//Project/Content/Example_05.uasset#6 - C:\Unreal\Project\Content\Example_05.uasset
//Project/Content/Example_06.uasset#1 - C:\Unreal\Project\Content\Example_06.uasset
//Project/Content/Example_07.umap#7 - C:\Unreal\Project\Content\Example_07.umap
//Project/Content/Example_08.umap#73 - C:\Unreal\Project\Content\Example_08.umap
C:\Unreal\Project\Content\Example_09.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_10.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_11.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_12.uasset - file(s) not on client.
C:\Unreal\Project\Content\Example_13.uasset - file(s) not on client.

Думаю, можно также отметить, что команда p4 выведет «файл(ы) не на клиенте» в stderr, поскольку это ошибка/предупреждение, обнаруженное после того, как я отказался от PowerShell и просто сделал это на Python.

🤔 А знаете ли вы, что...
PowerShell - это мощный скриптовый язык и среда командной строки для управления Windows-системами.


71
1

Ответ:

Решено

Объединив усилия всех:

# Get the files
Get-ChildItem -Recurse -Include ('*.uasset', '*.umap') -Attributes !ReadOnly 'C:\Unreal\Project\Content' |
    # run "p4 have" on every file
    # we are only interested in the results sent to stdErr\Error Stream, so redirect it to stdOut\Success Stream
    ForEach-Object { p4 have $_.FullName 2>&1 } | 
    # Filter keeping only the ones we need
    Where-Object { $_ -like '*not on client.' } | 
    # for each string, remove the undesidered parts(everything after the filename)
    ForEach-Object { $_.Substring($_.IndexOf(' - file(s)')) }

Он возвращает строковый массив имен файлов с полным путем.