0

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

mklement0
  • 382,024
  • 64
  • 607
  • 775
Jamal
  • 21
  • 3

1 Answers1

2

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.


Local variables in PowerShell vs. in POSIX-like shells (e.g., Bash)

$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.

    • Unlike POSIX-like shells (except 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].
      A variable with scope $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.

    • However, PowerShell offers explicit access to ancestral scopes, namely via the $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.

mklement0
  • 382,024
  • 64
  • 607
  • 775