I'm currently learning PowerShell, starting with the basics, and I've gotten to arrays. More specifically, looping arrays. I noticed that when declaring an array by itself, it's just simply written as
$myarray = 1, 2, 3, 4, 5
However, when an array is being declared with the intention of it being looped, it is written as
$myarray = @(1, 2, 3, 4, 5)
Out of curiosity, I tried running the code for looping through the array both with and without the @ sign just to see if it would work and it was displayed within the string I created in the exact same way for both.
My question is what is the purpose of the @ sign? I tried looking it up, but couldn't find any results.
CodePudding user response:
It's an alternative syntax for declaring static arrays, but there are some key details to understanding the differences in syntax between them.
@()
is the array sub-expression operator. This works similarly to the group-expression operator ()
or sub-expression operator $()
but forces whatever is returned to be an array, even if only 0 or 1 element is returned. This can be used inline wherever an array or collection type is expected. For more information on these operators, read up on the Special Operators in the documentation for PowerShell.
The 1, 2, 3, 4
is the list-expression syntax, and can be used anywhere an array is expected. It is functionally equivalent to @(1, 2, 3, 4)
but with some differences in behavior than the array subexpression operator.
@( Invoke-SomeCmdletOrExpression )
will force the returned value to be an array, even if the the expression returns only 0 or 1 element.
# Array sub-expression
$myArray = @( Get-Process msedge )
Note this doesn't have to be a single cmdlet call, it can be any expression, utilizing the pipeline how you see fit. For example:
# We have an array of fruit
$fruit = 'apple', 'banana', 'apricot', 'cherry', 'a tomato ;)'
# Fruit starting with A
$fruitStartingWithA = @( $fruit | Where-Object { $_ -match '^a' } )
$fruitStartingWithA
should return the following:
apple
apricot
a tomato ;)
Here is some more information about arrays in PowerShell, as well as the Arrays specification for PowerShell itself.
CodePudding user response:
The operator you're looking for documentation on consists not only of the @
but the (
and )
too - together they make up @()
, also known as the array subexpression operator.
It ensures that the output from whatever pipeline or expression you wrap in it will be an array.
To understand why this is useful, we need to understand that PowerShell tends to flatten arrays! Let's explore this concept with a simple test function:
function Test-PowerShellArray {
param(
$Count = 2
)
while($count--){
Get-Random
}
}
This function is going to output a number of random numbers - $Count
numbers, to be exact:
PS ~> Test-PowerShellArray -Count 5
652133605
1739917433
1209198865
367214514
1018847444
Let's see what type of output we get when we ask for 5 numbers:
PS ~> $numbers = Test-PowerShellArray -Count 5
PS ~> $numbers.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Alright, so the resulting output that we've stored in $numbers
is of type [Object[]]
- this means we have an array which fits objects of type Object
(any type in .NET's type system ultimately inherit from Object
, so it really just means we have an array "of stuff", it could contain anything).
We can try again with a different count and get the same result:
PS ~> $numbers = Test-PowerShellArray -Count 100
PS ~> $numbers.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
So far so good - we collected multiple output values from a function and ended up with an array, all is as expected.
But what happens when we only output 1 number from the function:
PS ~> $numbers = Test-PowerShellArray -Count 1
PS ~> $numbers.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType
Say what? Now we're getting System.Int32
- which is the type of the individual integer values - PowerShell noticed that we only received 1 output value and went "Only 1? I'm not gonna wrap this in an array, you can have it as-is"
For this reason exactly, you might want to wrap output that you intend to loop over (or in other ways use that requires it to be an array):
PS ~> $numbers = Test-PowerShellArray -Count 1
PS ~> $numbers.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType
PS ~> $numbers = @(Test-PowerShellArray -Count 1) # @(...) saves the day
PS ~> $numbers.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array