Perldocs only indicate that foreach loops "iterates over a normal list value" https://perldoc.perl.org/perlsyn.html#Foreach-Loops, but I sometimes see them with string arguments, such as the following examples:
foreach (`curl example.com 2>/dev/null`) {
# iterates 50 times
}
foreach ("foo\nbar\nbaz") {
# iterates just 1 time. Why?
}
Is the behavior of passing a string like this defined? Separately, why the disparate results from passing the string returned by a backticked command, and a literal string, as in the example?
In scalar context, backticks return a single scalar containing all the output of the enclosed command. But foreach (...) evaluates the backticks in list context, which will separates the output into a list with one line per element.
The question revolves around the context, a critical concept for many things in Perl.
The foreach loop needs a list to iterate over, so it imposes the list context to build the list values you saw mentioned in docs. The list may be formed with literals, qw(a b c), and may have one element; this is your second example, where one string is given, forming the one-element list that is iterated over.
The list can also come from an expression, that is evaluated in the list context; this is your first example. Many operations yield different returns based on context, and qx is such an operator as explained in mob's answer. This is something to note and be careful with. An expression may also return a single value regardless of context; then it is simply used to populate the list.
From perldoc -f qx:
In list context, returns a list of lines (however you've defined lines with $/ or $INPUT_RECORD_SEPARATOR), or an empty list if the command failed.
From perldoc perlsyn:
Compound statements
[...]
LABEL foreach VAR (LIST) BLOCK
A string is not a list. If you want to iterate over the characters in a string you'll need
foreach my $character (split('', "foo\nbar\nbaz")) {
I think you might be confusing Perl with Python:
>>> for c in "foo\nbar\nbaz":
... print c
...
f
o
.... remainder deleted ....
a
z
>>>
As pointed out by the other answers backticks/qx{} return a list of output lines from the executed command in list context.
Related
I am new o scripting in powershell and am from a Python background. I want to know if I'm doing this right.
I created this array and want to extract each item one by one
$M365_E3_Grps = ("O365-CHN-DomainUser,O365-Vendor-Exchange-User")
ForEach ($Indiv_Grp in $M365_E3_Grps) {
ForEach ($Indiv_Grp in $M365_E3_Grps) {
`$ADGroup = $Indiv_Grp$ADGroup = $Indiv_Grp`
I want to know if we can extract vals with a for loop like this and assign it to a variable like this.
Construct of your array
Your array is not quite correct and will be populated as a string. To create a string array you will need to quote each item in comma separated list. The parentheses are also not required.
$M365_E3_Grps = "O365-CHN-DomainUser","O365-Vendor-Exchange-User"
Your foreach keyword syntax is however correct, even if the formatting in your question was slightly off.
foreach ($Indiv_Grp in $M365_E3_Grps) {
# Assigning $Indiv_Grp to $ADGroup here is kind of redundant since
# the value is already assinged to $Indiv_Grp
$Indiv_Grp
}
I cannot exactly understand how the following snippet works:
my $str = 'abc def ghi';
my $num = () = $str =~ /\w+/g;
say $num; # prints the word count, 3
I know that $str =~ /\w+/g returns a list of the words which, apparently, is conveyed to the leftmost assignment. Then $num imposes a scalar context on that list and becomes 3.
But what does () = ('abc', 'def', 'ghi') mean? Is it something like my $a = my #b = (3, 5, 8)? If so, how is the list at the rightmost side transferred to $num at the leftmost side?
Each perl operator has specific behavior in list and scalar context. Operators give context to their operands, but receive context from what they are an operand to.
When a list assignment is placed in scalar context, it returns the number of elements on the right side of the assignment. This enables code like:
while (my #pair = splice(#array, 0, 1)) {
There's nothing special about how = () = is handled; you could just as well do = ($dummy) = or = (#dummy) =; the key part is that you want the match to be list context (producing all the possible matches) and then to just get a count of them.
So you do a list assignment (which is what = does whenever there's either a parenthesized expression or an array or slice as the left operand) but since you don't actually want the values, you can use an empty list. And then place that in scalar context; in this case, using the list assignment as the right operand to a scalar assignment.
Nowadays fewer people start learning Perl, one of reason is it has some obscure code like your example.
Check the perlsecret page for Saturn https://metacpan.org/pod/distribution/perlsecret/lib/perlsecret.pod#Goatse
=( )=
(Alternate nickname: "Saturn")
If you don't understand the name of this operator, consider yourself lucky. You are advised not to search the Internet for a visual explanation.
The goatse operator provides a list context to its right side and returns the number of elements to its left side. Note that the left side must provide a scalar context; obviously, a list context on the left side will receive the empty list in the middle.
The explanation is that a list assignment in scalar context returns the number of elements on the right-hand side of the assignment, no matter how many of those elements were actually assigned to variables. In this case, all the elements on the right are simply assigned to an empty list (and therefore discarded).
I am a bit confused about Scala string split behaviour as it does not work consistently and some list elements are missing. For example, if I have a CSV string with 4 columns and 1 missing element.
"elem1, elem2,,elem 4".split(",") = List("elem1", "elem2", "", "elem4")
Great! That's what I would expect.
On the other hand, if both element 3 and 4 are missing then:
"elem1, elem2,,".split(",") = List("elem1", "elem2")
Whereas I would expect it to return
"elem1, elem2,,".split(",") = List("elem1", "elem2", "", "")
Am I missing something?
As Peter mentioned in his answer, "string".split(), in both Java and Scala, does not return trailing empty strings by default.
You can, however, specify for it to return trailing empty strings by passing in a second parameter, like this:
String s = "elem1,elem2,,";
String[] tokens = s.split(",", -1);
And that will get you the expected result.
You can find the related Java doc here.
I believe that trailing empty spaces are not included in a return value.
JavaDoc for split(String regex) says: "This method works as if by invoking the two-argument split method with the given expression and a limit argument of zero. Trailing empty strings are therefore not included in the resulting array."
So in your case split(String regex, int limit) should be used in order to get trailing empty string in a return value.
I have a loop for example :
for my $something ( #place[1..$#thing] ) {
}
I don't get this statement 1..$#thing
I know that # is for comments but my IDE doesn't color #thing as comment. Or is it really just a comment for someone to know that what is in "$" is "thing" ? And if it's a comment why was the rest of the line not commented out like ] ) { ?
If it has other meanings, i will like to know. Sorry if my question sounds odd, i am just new to perl and perplexed by such an expression.
The $# is the syntax for getting the highest index of the array in question, so $#thing is the highest index of the array #thing. This is documented in perldoc perldata
.. is the range operator, and 1 .. $#thing means a list of numbers, from 1 to whatever the highest index of #thing is.
Using this list inside array brackets with the # sigill denotes that this is an array slice, which is to say, a selected number of elements in the #place array.
So assuming the following:
my #thing = qw(foo bar baz);
my #place = qw(home work restaurant gym);
then #place[1 .. $#thing] (or 1 .. 2) would expand into the list work, restaurant.
It is correct that # is used for comments, but not in this case.
it's how you define a range. From starting value to some other value.
for my $something ( #place[1..3] ) {
# Takes the first three elements
}
Binary ".." is the range operator, which is really two different
operators depending on the context. In list context, it returns a list
of values counting (up by ones) from the left value to the right
value. If the left value is greater than the right value then it
returns the empty list. The range operator is useful for writing
foreach (1..10) loops and for doing slice operations on arrays. In the
current implementation, no temporary array is created when the range
operator is used as the expression in foreach loops, but older
versions of Perl might burn a lot of memory when you write something
like this:
http://perldoc.perl.org/perlop.html#Range-Operators
In essence, I want to take an array and create a single string with the elements of said array separated by a newline.
I have an array named $zones. Outputting the reference to $zones confirms it's an array.
The following code:
print_log(Dumper($zones));
print_log('-------');
print_log(Dumper(join("\n",$zones)));
results in the following output
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = [
'fake.com25',
'fake.com2',
'fake.com27',
'fake.com43',
'fake.com41',
'fake.com40',
'fake.com39',
'fake.com37',
'fake.com36',
'fake.com35',
'fake.com31',
'fake.com56',
'fake.com55',
'fake.com54',
'fake.com53',
'fake.com52',
'fake.com51',
'fake.com50',
'fake.com49',
'fake.com48',
'fake.com42',
'fake.com38',
'fake.com34',
'fake.com33',
'fake.com32',
'fake.com30',
'fake.com29',
'fake.com28',
'fake.com26',
'fake.com24',
'fake.com23',
'fake.com69',
'fake.com68',
'fake.com67',
'fake.com66',
'0',
'fake.com44',
'fake.com45',
'fake.com46',
'fake.com278'
];
[2013-06-15 16:23:29 -0500] info [dnsadmin] -------
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = 'ARRAY(0x170cf0d8)';
I really don't want to loop over this array manually. Can someone explain why the join() function is returning the name of the type along with a hex number?
How to do is explained well by user1937198, but why it works this way?
It's simple:
$zones is not an array. It's an array reference.
join works on lists. So if you do:
join("\n",$zones)
You essentially are calling join on a single-element list. And the element is a reference, which happens to stringify to ARRAY(0x170cf0d8).
To make it work correctly you have to dereference it, and it is done by prefixing with real datatype (# or %, or in some cases $).
This can be written like this: #$zones, or (some, including me, say that it's more readable) as: #{ $zones }.
This is important when you're having nested structures, because while you can have plain array as a variable, when you're dealing with nested data structures, it's always references.
what you want is join("\n",#{$zones}))
$zones is array reference and to join array values you have to dereference it first by prefixing scalar $zones with #
print_log(Dumper(join("\n",#$zones)));
For more info there is short tutorial on references:
http://perldoc.perl.org/perlreftut.html#NAME