I have this strange observation:
I want to run an expression for as many times as there are files.
Yet, the following script always executes only once, no matter how many files are found by Get-ChildItem
:
(Get-ChildItem -Filter '*.png'), (Get-ChildItem -Filter '*.jpg') |
Sort-Object -Property 'Name' |
ForEach-Object -Begin { $idx = 0 } -Process { $idx; $idx; }
If I replace the expression with $_
, all rows are returned as expected:
(Get-ChildItem -Filter '*.png'), (Get-ChildItem -Filter '*.jpg') |
Sort-Object -Property 'Name' |
ForEach-Object -Begin { $idx = 0 } -Process { $_; }
CodePudding user response:
As Mathias points out, (...), (...)
creates a nested array, which is not your intent (the ,
operator constructs an array from its operands, even if those operands are themselves arrays).
The best way to provide output from multiple commands as pipeline input is to use &
(or .
, if you need the commands to run directly in the caller's scope) with a script block ({ ... }
), in which, as usual you can separate commands with ;
:
& { Get-ChildItem -Filter *.png; Get-ChildItem -Filter *.jpg } |
Sort-Object -Property Name |
ForEach-Object -Begin { $idx = 0 } -Process { $idx; $idx; }
This approach streams the command output, whereas use of $(...)
or @(...)
(which in this particular case can be used interchangeably) - $(Get-ChildItem -Filter *.png; Get-ChildItem -Filter *.jpg)
or @(Get-ChildItem -Filter *.png; Get-ChildItem -Filter *.jpg)
- collects all output first and then sends it to the pipeline.
An simplified version of your command that makes do with a single Get-ChildItem
call, using the -Path
parameter's support for multiple wildcard patterns:
Get-ChildItem -Path *.png, *.jpg |
Sort-Object -Property Name |
ForEach-Object -Begin { $idx = 0 } -Process { ( $idx) }
-Filter
is usually preferable, because it filters at the source, but it only supports one wildcard pattern; while-Path
, which makes PowerShell filter the results, is noticeably slower, the overhead from extraGet-ChildItem
calls may negate that advantage.- There's also
-Include
/-Exclude
, which also filter on the PowerShell side, but, unfortunately, they do not work as one would intuitively expect: see this answer.
- There's also
Also note the use of
(...)
around$idx
, which causes the updated value to also be output.