#powershell #filter #file-extension #get-childitem #write-host
#powershell #Фильтр #расширение файла #get-childitem #запись-хост
Вопрос:
Как я уже упоминал в вопросе, это похоже на ошибку в движке Powershell.
Когда я пытаюсь распечатать файлы в текущем каталоге (где также присутствует указанный сценарий powershell), исключив некоторые типы файлов (расширения), он ничего не печатает. Например. приведенные ниже коды выводят содержимое текущей папки в консоли Powershell:
gci
gci -pa .
Оба приведенных выше кода выводят содержимое каталога, как показано ниже:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 20-09-2020 22:37 835799796 file1.mkv
-a---- 20-09-2020 22:25 148 file1.srt
-a---- 23-09-2020 04:53 357 scriptv1.ps1
-a---- 20-09-2020 22:25 678 file1.txt
Но когда я запускаю приведенный ниже код, он ничего не печатает, когда он должен печатать file1.txt:
$excluded = @('*.mkv','*.mp4','*.srt','*.sub','*.ps1')
Get-ChildItem -Exclude $excluded | Write-Host { $_.FullName }
Кто-нибудь может помочь выяснить, почему это происходит и как получить то, что я упомянул?
Ответ №1:
Использование -Exclude
with Get-ChildItem
не интуитивно понятно. Чтобы получить согласованные результаты Get-ChildItem
, вы должны указать свой путь с *
помощью или использовать -Recurse
переключатель. Если вы не хотите выполнять рекурсию, вы можете просто использовать Get-Item
с *
указанием пути.
# Works but includes all subdirectory searches
Get-ChildItem -Path .* -Exclude $excluded
Get-ChildItem -Path .* -Exclude $excluded -File
Get-ChildItem -Path . -Exclude $excluded -File -Recurse
# Best results for one directory
Get-Item -Path .* -Exclude $excluded
Причина, по которой следует использовать рекурсию, заключается в том, что -Exclude
значения сначала применяются к листу -Path
значений. Если какое-либо из этих исключений соответствует вашему целевому каталогу, оно будет исключено и не позволит отображать ни один из его элементов. См. Ниже:
$path = 'c:temp'
# produces nothing because t* matches temp
Get-ChildItem -Path $path -Exclude 't*'
Ответ №2:
вы правильно используете параметр исключения в своем gci
примере, но там, где он может завершиться ошибкой в вашей консоли, он автоматически обрабатывает результаты, write-host
поскольку он не обрабатывает блок { .. }
сценария, как foreach-object
это было бы для отдельных элементов. Ошибка молчания должна быть:
Write-Host: входной объект не может быть привязан к каким-либо параметрам для команды либо потому, что команда не принимает конвейерный ввод, либо потому, что ввод и его свойства не соответствуют ни одному из параметров, которые принимают конвейерный ввод.
В этом отношении правильная краткая foreach-object
запись конвейера будет:
$excluded = @('*.mkv','*.mp4','*.srt','*.sub','*.ps1')
Get-ChildItem -Exclude $excluded | % { Write-Host $_.FullName }
Что касается молчащих ошибок, я предполагаю, что для вашего сеанса установлено значение быть Silent
, которое вы можете проверить с $ErrorActionPreference
помощью переменной. Если вы хотите просмотреть все ошибки — в неблокирующем режиме вы можете установить это Continue
значение, например:
$ErrorActionPreference='Continue'
Соответствующие страницы и примеры PS7:
Write-Host
: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-host?view=powershell-7Foreach-Object
: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/foreach-object?view=powershell-7Preference
Переменные: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7
Ответ №3:
Get-ChildItem -Exclude $excluded | Write-Host { $_.FullName }
не должно завершаться без сбоев, если все дочерние элементы в вашем каталоге не будут исключены вашим фильтром.
Если вы попытаетесь выполнить запуск Get-ChildItem | Write-Host { $_.FullName }
в непустом каталоге, он должен выдать ошибку, аналогичную этой:
Write-Host: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
Причина в том, что Write-Host
невозможно принять массив в качестве параметра (и мы знаем, что это массив (Get-ChildItem).GetType()
).
Поэтому вам необходимо сначала выполнить итерацию по элементам массива, используя ForEach-Object
или один из его псевдонимов: foreach
или %
.
$excluded = @('*.mkv','*.mp4','*.srt','*.sub','*.ps1')
Get-ChildItem -Exclude $excluded | ForEach-Object { Write-Host $_.FullName }
Get-ChildItem -Exclude $excluded | foreach { Write-Host $_.FullName }
Get-ChildItem -Exclude $excluded | % { Write-Host $_.FullName }