I'm wondering how I can append PowerShell function arguments to a program command?
I want something like this:
function foo($x, $y, $z) {
docker run $x $y $z
}
So that calling PS>foo alone would be the equivelant to PS>docker run, and PS>foo a b c to PS>docker run a b c.
This seems like a question that must have an answer here somewhere, but I am unable to find it. I'm not sure whether I'm just phrasing my searches poorly. Apologies in advance if so.
Thanks!
Grab the argument values from $PSBoundParameters.Values:
function foo($x, $y, $z) {
docker run $PSBoundParameters.Value
}
As pointed out in the comments, $PSBoundParameters doesn't guarantee insertion order, an alternative approach would be to take a single argument of arrays with the ValueFromRemainingArguments parameter flag set:
function foo {
param(
[Parameter(Mandatory=$false,ValueFromRemainingArgumemnts)]
[string[]]$dockerArgs
)
$dockerArgs = #('run';$dockerArgs)
& docker $dockerArgs
}
Related
I am a perl newb.
Unfortunately, eval doesn't work the way I'm expecting
My mock example:
my $filter = 'return false;';
my $filterFunc = sub{ eval{ $filter } } ;
while (my $entry = readNextEntry()){
print "Eval:".$filterFunc->( $entry )."\n";
}
When I run this, I get the literal "return false;" being returned from every pass (rather than the function getting evaluated). I've tried a couple of variations, but I'm not hitting the magic combination.
A note on security implications:
As I am the user, I don't have security concerns about what the passed in code does.
My intent is to pull in multiple sources and filter out stuff based on parameters, since I don't know what parameters are going to be useful, I thought I could pass in some text, eval the text into an anonymous function, and run the function for each record (a filter function). As I am the user, I don't have security concerns about what the passed in code does.
You need to do string eval, not block eval.
my $filterFunc = sub{ eval{ $filter } } ;
The eval BLOCK is like a try/catch mechanism. It does not evaluate arbitrary code. It catches errors in the code inside the block. What you want is string eval.
my $filterFunc = sub{ eval $filter };
Here's an example implementation of what I think you are trying to do:
$ perl -E 'my $filter = sub { my $f = shift; eval $ARGV[0]; }; for ( 1 .. 10 ) { say $_ if $filter->($_) }' '$f % 2'
1
3
5
7
9
However, there is no false in Perl. That's not a keyword. Unless you have sub false somewhere, this might give you a syntax error, depending on if you have use strict or not.
You should read up on eval.
If all you want is a $filterFunc that returns something false, use 0 instead. Note that the literal string "return false;" is true in Perl.
I have an object ($p), and in the initialization I have $this->{list} = [];
Later, I fill up the array with objects of another class (q), and can access them as #{$self{list}} in another subroutine in class [p]. I am trying to sort this array, as
my #slist = sort $self->point_sort, #{$self->{list}};
point_sort is defined as a subroutine in class p, and I am getting
Can't call method "getQval" on an undefined value at p.pm line 64
getQval is a subroutine defined in object q, instances of which populate the {list}. I am trying to do
my $v1 = $a->getQval;
my $v2 = $b->getQval;
in the subroutine point_sort. Any suggestions? TIA.
Edit:
Changed the call to
my #slist = sort { $self->point_sort ($a,$b) } #{$self->{list}};
In point_sort, I have now
my ($c, $d) = #_;
my $val1 = $c->getVarVal;
The error:
Can't locate object method "getVarVal" via package "packageP" at ...
I think it has something to do with packages, not sure what it is. It is looking in package p, whereas I want it to look at package q.
Edit:
I did a print on $c above - perl thinks it is an object of class p - a hashtable
You're not actually using $self->point_sort as a comparison function here. It's being called immediately (with no arguments and before $a and $b are set, hence the error), and its return value (if it got that far) would then be used as the comparator.
The easiest fix is to pass $a and $b explicitly:
my #slist = sort { $self->point_sort($a, $b) } #{$self->{list}};
Then receive them as regular arguments in point_sort.
The syntax of sort are:
sort SUBNAME LIST # Sort the list using named function as the comparison function
sort BLOCK LIST # Sort the list using the block as the comparison function
sort LIST # Sort the list using the default comparison function.
You want $self->point_sort to be used as the comparison function, but you used the third syntax rather than one of the two that allows you to specify a comparison function.
Perhaps you want
sort { $self->point_sort($a, $b) } #{ $self->{list} }
is clear n
This function accepts two values and a function, and calls that function with the two values:
function abc ($a, $func, $b) { &$func $a $b }
Define a function to pass:
function bcd ($x, $y) { $x + $y }
Pass bcd to abc:
abc 10 bcd 20
The result is 30.
It appears that the bcd function object itself isn't being passed, but the string "bcd". Then abc invokes bcd by its name.
Is this considered an acceptable way to pass a function to another function? Most examples I've seen suggest passing a function in a script block which will be invoked in the receiving function. However that approach is more verbose than the above method.
You're correct that it works, as long as the scope doesn't change enough to invalidate the naming. So it's a bit fragile for truly general code; I wouldn't recommend it even in your profile script, for example. (Speaking from some painful experience with insufficiently general profile functions here.)
However, consider this sample, which is even shorter and more robust:
function abc($a, $func, $b) { &$func $a $b }
abc 10 { param($a, $b); $a+$b } 20
(Prints out 30.) You can do whatever you'd normally want with that param block, including validation.
abc 10 {param([parameter(Mandatory=$true)]$a, [parameter(Mandatory=$true)]$b); $a+$b} 20
Alternatively, predefine the function like this:
$bcd = { param($a, $b); $a+$b }
And continue as usual:
abc 10 $bcd 20
Unless there's some reason the passed function call needs to be isolated to it's own scope you can simplify that by just passing a script block and invoking it in the function's local scope:
function abc($a, $func, $b) {.$func}
abc 10 {$a+$b} 20
30
Guys I'm new to Perl and I am now in reference chapter, and this topic confuses me. I understand the concept of reference since I know C programming too. In the book I am reading says:
"Not only can you dereference a simple variable name, you can also dereference the contents of a BLOCK. Anywhere you'd put an alphanumeric identifier as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type."
I need an example on this part- "anywhere you'd put an alphanumerc identifier as part of a variable.... you can replace the identifier with a block" - exactly how would that happen?
and this example too:
&{ $dispatch{$index} }(1, 2, 3);
Can somebody explain that code.
The quoted paragraph is saying that you're not limited to doing
my $handler = $displatch{$type} or die; # Arbitrary code
my $ref = $handler->(); # Arbitrary code
my #a = #$ref;
You can also do
my #a = #{ my $handler = $displatch{$type} or die; $handler->() };
Same goes for other dereferences.
$BLOCK
$BLOCK[ ... ]
$BLOCK{ ... }
#BLOCK
#BLOCK[ ... ]
#BLOCK{ ... }
%BLOCK
&BLOCK
&BLOCK( ... )
*BLOCK
$index contains the name of a hash key. %dispatch is the hash with said key. The value associated with that key is a subroutine reference, which &{} dereferences. It's invoked with 1, 2, 3 as its arguments.
This is a fine enough example, although I would generally write:
$dispatch{$index}->(1, 2, 3)
sub sample_function1 {
...
}
sub sample_function2 {
...
}
%dispatch = ( 'f1' => \&sample_function1,
'f2' => \&sample_function2 );
$index = <STDIN>;
chomp $index;
&{ $dispatch{$index} }(1, 2, 3);
If the user enters f1 this will call sample_function1(1, 2, 3), if he enters f2 it will call sample_function2(1, 2, 3).
What the documentation is explaining is that you since you can write sample_function1(1, 2, 3), you can replace the function name with a block containing code that returns a function reference.
Take a look at the File::Find. You may have even used that before. It's one of the first Perl modules that many Perl programmers ever use.
The find command takes two arguments:
The second (we'll start with the simple one) is a list of directories I want to search.
The first argument is a bit trickier -- it's an actual subroutine my find command will use. The find command uses that subroutine to determine if a particular element in my directory tree matches the criteria I'm looking for. What find does is go through each and every element of my directory tree and passes that element to my subroutine. It's up to my subroutine to check the element to see if it passes muster.
Let's say I want to find all files in my directory that have the suffix of .txt. In Unix, I could do this:
$ find $directory -type f -name "*.txt"
In Perl, I create a subroutine called wanted. The find command will pass to my wanted subroutine an element in my directory via the $_ Perl variable. I can then test that element to see if it's a file that has a .txt suffix:
sub wanted {
return unless -f; #Return unless $_ is a file
return unless /\.txt$/; #Return unless that file has a `.txt` suffix
print "$Find::File::name\n"; #It's a file that ends with .txt. Print it.
}
Now, all I have to do is get my wanted subroutine as the first parameter of my find command:
find ( \&wanted, $directory );
That's all there is to it. A real life example that you will (if you haven't already) run into really soon. In C programming parlance, the wanted subroutine would be called a Callback routine.
I'm trying to make a simple swap function in PowerShell, but passing by reference doesn't seem to work for me.
function swap ([ref]$object1, [ref]$object2){
$tmp = $object1.value
$object1.value = $object2.value
$object2.value = $tmp
}
$a = 1
$b = 2
$a, $b
swap ([ref]$a) ,([ref]$b)
$a, $b
This SHOULD work, but no...
Output:
1
2
1
2
What did I do wrong?
Call like this:
swap ([ref]$a) ([ref]$b)
The mistake of using , is described in the Common Gotchas for PowerShell here on Stack Overflow.
By the way, PowerShell has a special syntax to swap values, and there isn't a need to use $tmp:
$a,$b = $b,$a
Firstly, you're calling it wrong. Putting a comma in the call to swap means you're passing an array of them to objects as the first parameter. If you were to correct it...
swap ([ref]$a) ([ref]$b)
...it would then work.