i want the equivalent of this code in PowerShell
function containsElement () {
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
help me please
You don't need a function for that in PowerShell, because it comes with collection-containment operators -contains
and -in
(they only differ by whether the array goes on the LHS or RHS):
# Sample value to test.
$element = 1
# Sample array to test against.
$array = 5, 3, 2, 1, 6
# Test if the value is in the array.
$contains = $element -in $array
# output the value of $contains
$contains
The above yields True
(the output representation of $true
), as expected.
Caveat: PowerShell, unlike traditional shells, has a rich type system based on .NET, which means that (implied) equality comparisons may not always work as expected; in short, due to automatic type conversions, the order of operands in a comparison matters, so that '0xa' -in 10, 'other'
is $true
, but 10 -in '0xa', 'other'
is not - see the bottom section of this answer for details.
If you do need to replicate your Bash function with the array elements passed as individual arguments:
function containsElement {
# Save the 1st argument passed and the remaining ones
# in separate local variables, using a destructuring assignment.
# $args is an automatic variable that contains the arguments
# passed as an array ([object[]]), akin to $@ in Bash.
$e, $arr = $args
# Test, and implicitly output the Boolean result.
$e -in $arr
}
# Sample call, equivalent of above.
containsElement 1 5 3 2 1 6
Also note that PowerShell communicates Boolean values as data (implicit or explicit [bool]
values), not via invisible status information (exit codes) the way POSIX-like shells such as Bash do - see the bottom section of this answer for more information.
$e
and $arr
in the function above are local variables, implicitly so; if you wanted to make that fact explicit, you could use $local:e, $local:arr = $args
, but that is never necessary, because assigning to a variable in PowerShell implicitly and invariably creates it in the local (current) scope.
This differs from POSIX-like shells, where assignment without local
either modifies a preexisting variable in a parent scope or, if there is none, implicitly creates the variable in the top-level (script) scope[1]:
As in POSIX-like shells, descendant scopes in PowerShell (child scopes and their children...) do see a local variable.
ksh
[1]), PowerShell also offers a way to create a truly local variable, i.e., a variable that is both visible and modifiable in the defining scope only, namely via the $private:
scope modifier: $private:var = 'truly local'
[2].$private
has the effective behavior of what you'd expect from a local variable in a lexically scoped compiled programming language such as C# (as opposed to dynamically scoped scripting languages).Unlike in POSIX-like shells, descendant scopes cannot modify a caller's local variable by unqualified assignment - or any ancestral scope's variables, for that matter.
$script:
and $scope:
scope specifiers, and also via the -Scope
parameter of the Get-Variable
and Set-Variable
cmdlets.See the bottom section of this answer for more information about PowerShell's scoping rules.
[1] Demonstration of scoping in POSIX-like shells
The followings script works in bash
, dash
and zsh
(bash
and dash
are frequently used as a system's default shell, /bin/sh
).
To make the script run in ksh
, you'd have to replace the local
keyword with typeset
and define the functions with the function
keyword (function a { ...
instead of a() { ...
), because ksh
doesn't understand local
and only creates local variable with the function
syntax.
Unlike the other POSIX-like shells mentioned, however, ksh
then creates a truly local variable not seen in descendant scopes, the same way PowerShell's $private:
scope does; in other words: local ksh
variables are invariably function-local, and descendant scopes never see them.
#!/usr/bin/env bash
a() {
local var='1' # create local variable.
echo " calling scope before: [$var]"
b # call function b
echo " calling scope after: [$var]"
}
b() {
echo " child scope before: [$var]" # calling scope's var. is visible
var='1a' # modifies the *caller's* var.
local var=2
var='2a' # modifies the *local* var.
echo " child scope after: [$var]"
newvar='hi' # assigning to a variable that doesn't exist in any scope
# on the call stack creates it in the *top-level* scope.
}
# Call function a()
a
# var. created in b() without `local` is now visible.
echo "script scope: [$newvar]"
This yields the following:
calling scope before: [1]
child scope before: [1]
child scope after: [2a]
calling scope after: [1a]
script scope: [hi]
[2] Demonstration of the $private:
scope in PowerShell
# & { ... } executes ... in a child scope.
# Referencing a variable by itself implicitly outputs it (implicit `echo `).
PS> $var = 'outer'; & { $private:var = 'inner'; $var; & { $var } }
inner
outer
That is, the private $var
was only visible directly inside the outer { ... }
; the nested { ... }
again saw the grandparent scope's $var
.