What is correct syntax for arrays in powershell? - arrays

Example1:
Note 2: The comma is also used so
separate items in an array {0,-30}
Example2:
To create an array, we create a
variable and assign the array. Arrays
are noted by the “#” symbol. Let’s
take the discussion above and use an
array to connect to multiple remote
computers: $strComputers =
#(“Server1″, “Server2″, “Server3″)
So, which one is correct or what is the difference ?

Example 2 uses the array cast syntax which allows a single element, for example, to be treated as an array:
$myList = #("Hello")
Essentially, it allows anything between the parenthesis to be treated as an array including the output from other commands:
$myArray = #(Get-Process Excel)
Alternatively you can just create an array by specifying a comma separated list:
$myArray = "hello", "world", "again"
(The curly brackets are not needed)

You can also attain a single element array by prepending the , operator to a single value:
[PS] C:\>$a = ,"Hello World"
[PS] C:\>$a.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
[PS] C:\>$a.count
1

Related

Powershell Separating a string into an array and iterating through

I'm trying to separate a string in the following format,
STANDARDWOFFPACK_FACULTY ; FLOW_FREE
So that each entry in the string is an item within an array I can iterate through to do a function against. Any suggestions on how I would achieve this array would be greatly appreciated.
You can use the split() method:
$myString= 'STANDARDWOFFPACK_FACULTY ; FLOW_FREE'
$myString.split(';')
Which gives:
STANDARDWOFFPACK_FACULTY
FLOW_FREE
Note that this includes the extra spaces as part of the separate strings. If you want rid of those, do this:
$myString.split(';').Trim()
To get the output in an array, simply capture it in a variable:
$myArray = $myString.split(';').Trim()
You can confirm it is an array with the GetType() method:
$myArray.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array

Check for a random element in an array and return it if true

I've got several arrays of varying length that may contain an element which begins with foo (the name length varying as well), if this element exists I want to return it, e.g. foo-f-o-o.
I know how to check for its existence, I successfully tested in
{
"arr": [
"foo-f-o-o", "bar", "baz", "qux", "quux", "corge", "grault"
]
}
with the command type file.json | jq ".arr|contains([\"foo\"])" and I correctly received true.
However, I'm looking for these steps:
Detect if an element foo* exists
If yes, return that element's name, in the given case: foo-f-o-o
If not, return false
The element foo.* could be at any position of the array, that means something like jq -r ".arr|.[0]" is not an option here.
Is there a way to apply a regex like /^foo.*/ in jq for the matching value?
You don't need regex for this particular case, use startswith:
first(.arr[] | select(startswith("foo"))) // false
If you need all matching elements:
(.arr[] | select(startswith("foo"))) // false

Why is a leading comma required when creating an array?

I want to create an array containing arrays of two numbers. Pretty straightforward. However, If I do not provide a leading comma before the first array, it is incorrect. Why is this leading comma required?
PS C:\src\powershell> Get-Content .\fr-btest.ps1
$files1 = #(
#(4, 1024)
, #((7), (16))
)
$files1
$files1.GetType()
$files1.Length
$files1.Count
'========'
$files2 = #(
, #(4, 1024)
, #((7), (16))
)
$files2
$files2.GetType()
$files2.Length
$files2.Count
PS C:\src\powershell> .\fr-btest.ps1
4
1024
7
16
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
3
3
========
4
1024
7
16
True True Object[] System.Array
2
2
#() is the array subexpression operator, which works differently than array construction operators you may be used to from other languages. The operator evaluates the nested subexpression and returns the output of that expression as an array. Meaning you can do something like this:
#(
Write-Output 'foo'
Get-Content 'C:\some\file.txt'
Test-Connection '192.168.23.42' -Count 1
)
and have an array come out.
For your first example this means that the two statements #(4, 1024) and , #((7), (16)) are evaluated individually, and the collective output of the two statements is then returned as an array.
The first statement (#(4, 1024)) outputs two integers, but the second statement (, #((7), (16))) outputs an array of two integers. That is because the leading comma in that statement is interpreted as the unary array construction operator (or comma operator), so you get an array nested in another array, and only the outer array is unrolled during output.
Essentially, your expression is the same as
$files1 = #(
4
1024
, #(7, 16)
)
or
$files1 = 4, 1024, #(7, 16)
Your second example avoids this pitfall, because both nested arrays are prepended with the unary array construction operator and thus protected from being completely unrolled.
With that said, I would recommend to define arrays in a more clear-cut way, e.g. like this:
$files1 = #(4, 1024),
#(7, 16)
or (using grouping expressions instead of array subexpressions) like this:
$files1 = (4, 1024),
(7, 16)
to avoid surprises like the one you observed. The outer #() isn't necessary for defining an array here. PowerShell automatically detects that via the trailing comma at the end of the first line.
For further information see about_Operators.
The key to understanding the Array subexpression operator #( ) is the realization that you don't need it to create arrays, instead arrays are created with the Comma operator ,
As a binary operator, the comma creates an array. As a unary operator,
the comma creates an array with one member. Place the comma before the member.
$myArray = 1,2,3
$SingleArray = ,1
$xs = (1,2,3), (4,5,6) # Count: 2
$ys = (1,2,3),
(4,5,6) # Count: 2
Now consider
# A - two expressions, each expression yields one array of size 3
(1,2,3)
(4,5,6)
# B - one expression resulting in an array of two elements
(1,2,3),
(4,5,6)
# C - similar to A except the sizes are 3 and 1
# (the second array contains a single element)
(1,2,3)
,(4,5,6)
And the final step is to realize that
in essence, the #(...) operation is syntactic sugar for
[array] $(...)
as explained by the PowerShell Team Blog (The link was given by Christopher G. Lewis answer). Although the meaning and limitations of in essence is not entirely clear to me.
Powershell uses both a comma and a line break as an array separator. Your first declare:
$files1 = #(
#(4, 1024)
, #((7), (16))
)
Creates the following:
$files1[0] = 4
$files1[1] = 1024
$files1[2] = #(7,16)
Your second declare
$files1 = #(
, #(4, 1024)
, #((7), (16))
)
Creates the following:
$files1[0] = #(4, 1024)
$files1[1] = #(7, 16)
As to the parsing decision, it is dependent on the first non-white space character encountered on a line:
Array Literals In PowerShell
and
Understanding PowerShell Parsing Modes

Understanding referencing within perl arrays and how data is accessed

I could do with some help on perl and how it handles its arrays. (A long time ago) I used to do quite a lot of coding (hacking would be a better description, never pretty work) using php, java, js, etc but for various reasons I'm using perl for a project and i'm struggling to work out why I'm finding arrays such a pain.
For example, the following code:
#inflightsequences=([1,6,[["SRCIP","1.2.3.4"],["DSTIP","5.6.7.8"]]],[2,2,[["SRCIP","1.2.3.4"],["DSTIP","5.6.7.8"]]]);
foreach (#inflightsequences) {print Dumper #_};
where the definition of the array creates this (printed using Dumper)
$VAR1 = [
1,
6,
[
[
'SRCIP',
'1.2.3.4'
],
[
'DSTIP',
'5.6.7.8'
]
]
];
$VAR2 = [
2,
2,
[
[
'SRCIP',
'1.2.3.4'
],
[
'DSTIP',
'5.6.7.8'
]
]
];
(NB I'll refer to the data inside the array using VAR1 and VAR2 from now on so its clear which block I'm referring to, regardless of whether thats actually what Dumper calls it)
...but the foreach outputs absolutely nothing, when I expected it to cycle twice and output whats in VAR1 first then in VAR2. However
print Dumper #inflightsequences[0];
print Dumper #inflightsequences[1];
does print out VAR1 and VAR2 as expected.
Then I extract the first item from the #inflightsequences array
#dataset = shift(#inflightsequences);
and I expected print $dataset[1] to print out the first value (1) in what was VAR1 and print $dataset[2] to print the second value (6) but no, to achieve what I expected I have to do print $dataset[0][0] and print $dataset[0][1]. Why the extra [0]?
And thus I have got myself completely confused....
Thanks
--Chris
What is confusing you is that the elements of Perl arrays are always scalar values. You make arrays of arrays by using references for those scalars.
You can create an array reference either by building a named array and taking its reference
my #data = ( 'a', 'b', 'c' );
my $array_ref = \#data;
or by creating an anonymous array
my $array_ref = [ 'a', 'b', 'c' ];
The only difference between these two is that the data can be accessed through the name #data in the first case as well as through the reference $array_ref. To access elements of an array through a reference, you use the arrow operator, so
$array_ref->[0]
is the same as
$data[0]
The reason your foreach loop prints nothing is that you are dumping the contents of the array #_ which you have never mentioned before and is empty. #_ is the array that is set within a subroutine to the actual parameters passed when that subroutine is called. It has no use otherwise.
Remembering that array elements are scalars, and that if you don't specify a loop control variable then Perl will use $_, what you should have written is
foreach (#inflightsequences) { print Dumper($_) }
or, more Perlishly,
print Dumper($_) for #inflightsequences
The same applies to your statement
#dataset = shift(#inflightsequences)
which, again, because the contents of #inflightsequences are scalars is removing the first array reference and putting it into #dataset, which is now just a one-element array containing an array reference. That means you have moved $inflightsequences[0] to $dataset[0], which is now equal to
[1, 6, [ ["SRCIP", "1.2.3.4"], ["DSTIP", "5.6.7.8"] ] ]
not forgetting that the square brackets create a reference to an anonymous array. So, like our $array_ref->[0] above, you can access the first element of this array using $dataset[0]->[0]. And because Perl allows you to remove the arrow operator between pairs of square brackets (and curly brackets if we're using hashes) you can contract that to $dataset[0][0] which happens to be the value 1.
I hope that helps. You would do well to read perlref and experiment a little. Note that the Data::Dump module produces output much superior to Data::Dumper, but you may need to install it as it isn't a core module. Once it's installed the code will look like
use Data::Dump;
dd \#inflightsequences;
#inflightsequences is an array of array references so
$r=shift(#inflightsequences)
print $r->[0]
will show 1
and
print $r->[1]
will show 6
doing
#dataset=shift(#inflightsequences)
Makes an array from the result from the shift. So it's a array with one element, the shift result, which is accessed as $dataset[0]. $dataset[0]->[1] will give 6, for example

How to reference a split expression in Perl?

I want to create a reference to an array obtained by a split in Perl.
I'm thinking something like:
my $test = \split( /,/, 'a,b,c,d,e');
foreach $k (#$test) {
print "k is $k\n";
}
But that complains with Not an ARRAY reference at c:\temp\test.pl line 3.
I tried a few other alternatives, all without success.
Background explanation:
split, like other functions, returns a list. You cannot take a reference to a list. However, if you apply the reference operator to a list, it gets applied to all its members. For example:
use Data::Dumper;
my #x = \('a' .. 'c');
print Dumper \#x
Output:
$VAR1 = [
\'a',
\'b',
\'c'
];
Therefore, when you write my $test = \split( /,/, 'a,b,c,d,e');, you get a reference to the last element of the returned list (see, for example, What’s the difference between a list and an array?). Your situation is similar to:
Although it looks like you have a list on the righthand side, Perl actually sees a bunch of scalars separated by a comma:
my $scalar = ( 'dog', 'cat', 'bird' ); # $scalar gets bird
Since you’re assigning to a scalar, the righthand side is in scalar context. The comma operator (yes, it’s an operator!) in scalar context evaluates its lefthand side, throws away the result, and evaluates it’s righthand side and returns the result. In effect, that list-lookalike assigns to $scalar it’s rightmost value. Many people mess this up becuase they choose a list-lookalike whose last element is also the count they expect:
my $scalar = ( 1, 2, 3 ); # $scalar gets 3, accidentally
In your case, what you get on the RHS is a list of references to the elements of the list returned by split, and the last element of that list ends up in $test. You first need to construct an array from those return values and take a reference to that. You can make that a single statement by forming an anonymous array and storing the reference to that in $test:
my $test = [ split( /,/, 'a,b,c,d,e') ];
Surround split command between square brackets to make an anonymous reference.
my $test = [ split( /,/, 'a,b,c,d,e') ];
Giving it a name has different semantics in that changes to the named variable then change what was referenced while each anonymous array is unique. I discovered this the hard way by doing this in a loop.

Resources