Home > front end >  Using an Index with foreach-object in powershell
Using an Index with foreach-object in powershell

Time:05-13

I have this code:

Get-ChildItem FOLDERNAMEHERE *.png| ForEach-Object { $_.Name } > fileNames.txt

It prints off a list of file Names, and I want to change it to out just print out an index of numbers instead of Names.

CodePudding user response:

To output sequence numbers starting with 1 (replace $i = 0 with $i = -1 to start with 0):

Get-ChildItem FOLDERNAMEHERE *.png |
  ForEach-Object -Begin { $i = 0 } -Process { (  $i) }

Note that the variable $i lives on after this command, and, if it preexisted before running the command, effectively changes it, because the script blocks passed to ForEach-Object run directly in the caller's scope.

The increment assignment operation ( ) is wrapped in (...) so as to also output the incremented value (assignment statements produce no output by default).

As an aside:

  • GitHub issue #13772 proposes introducing an automatic index variable for use in pipelines, such as $PSIndex, which would simplify the solution to:

    Get-ChildItem FOLDERNAMEHERE *.png | ForEach-Object { $PSIndex   1 }
    

Non-streaming alternative, using .., the range operator:

if ($count = (Get-ChildItem FOLDERNAMEHERE *.png).Count) {
  1..$count
}

Note: Non-streaming means that the results of the Get-ChildItem call are collected in full, up front in order to determine the upper limit for the sequence numbers.

Similarly, the 1..$count range operation collects the elements between the range endpoints in an array up front before beginning to produce visible output. See the comments for a discussion.

In other words: Go with the streaming, ForEach-Object-based solution if the Get-ChildItem command produces a lot of output objects and you want to start emitting sequence numbers as quickly as possible.

  • Related