эквивалент local в powershell, проверьте, содержится ли элемент в массиве - PullRequest
0 голосов
/ 12 апреля 2019

я хочу эквивалент этого кода в PowerShell

function containsElement () {
  local e
  for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
  return 1
}

помогите мне, пожалуйста

1 Ответ

2 голосов
/ 12 апреля 2019

Для этого вам не нужна функция в PowerShell, потому что она поставляется с операторами удержания коллекции
-contains и -in (они отличаются только тем, идет ли массив на LHS или 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

Выше приведено True (выходное представление $true), как и ожидалось.

Предостережение : PowerShell, в отличие от традиционных оболочек, имеет систему расширенного типа на основе .NET, что означает, что (подразумеваемое) сравнение на равенство может не всегда работать должным образом; короче говоря, из-за автоматического преобразования типов порядок операндов в сравнении имеет значение, так что '0xa' -in 10, 'other' равен $true, а 10 -in '0xa', 'other' нет - подробности см. в нижнем разделе этого ответа .


Если вам нужно скопировать функцию Bash с элементами массива, переданными как отдельные аргументы :

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

Также обратите внимание, что PowerShell передает логические значения как данные (неявные или явные [bool] значения), а не через невидимую информацию о состоянии (коды выхода), как POSIX-подобные оболочки, такие как как это делает Bash - см. нижнюю часть этого ответа для получения дополнительной информации.


Локальные переменные в PowerShell и в POSIX-подобных оболочках (например, Bash)

$e и $arr в функции выше являются локальными переменными, неявно так; если вы хотите сделать этот факт явным, вы можете использовать $local:e, $local:arr = $args, но это никогда не требуется, поскольку присваивание переменной в PowerShell неявно и неизменно создает ее в локальная (текущая) область действия .

Это отличается от POSIX-подобных оболочек , где назначение без local либо изменяет ранее существовавшую переменную в родительский область или, если таковая отсутствует, неявно создает переменную в верхнем уровне (сценарий) области действия [1]

  • Как и в POSIX-подобных оболочках, потомки областей в PowerShell (дочерние области и их дочерние элементы ...) делают см. локальную переменную .

    • В отличие от POSIX-подобных оболочек (за исключением ksh [1] ), PowerShell также предлагает способ создать действительно локальную переменную , т. Е. переменная, которая является видимой и изменяемой только в определяющей области, а именно через модификатор $private: scope : $private:var = 'truly local' [2] .
      Переменная с областью действия $private имеет эффективное поведение, которое можно ожидать от локальной переменной в лексически скомпилированном языке программирования, например C # (в отличие от динамически сценариев с областью действия языков).
  • В отличие от POSIX-подобных оболочек, области-потомки не могут изменять локальную переменную вызывающей стороны с помощью неквалифицированного присваивания - или любых переменных области предков, для это важно.

    • Однако PowerShell предлагает явный доступ к наследственным областям , а именно через спецификаторы области действия $script: и $scope: , а также через -Scope параметр командлетов Get-Variable и Set-Variable.

См. Нижний раздел этого ответа для получения дополнительной информации о правилах области действия PowerShell.


[1] Демонстрация определения объема в POSIX-подобных оболочках

Следующий скрипт работает в bash, dash и zsh (bash и dash часто используются в качестве системной оболочки по умолчанию, /bin/sh).

Чтобы скрипт выполнялся в ksh, вам нужно заменить ключевое слово local на typeset и определить функции с ключевым словом function (function a { ... вместо a() { ...), потому что ksh не понимает local и создает только локальную переменную с синтаксисом function.
В отличие от других упомянутых POSIX-подобных оболочек, однако, ksh затем создает действительно локальную переменную 1167 *, не видимую в дочерних областях, так же, как в области $private: PowerShell;другими словами: локальные ksh переменные неизменно локально-функциональные, а потомки никогда не видят их.

#!/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]"

Это приводит к следующему:

  calling scope before: [1]
    child scope before:   [1]
    child scope after:    [2a]
  calling scope after:  [1a]
script scope: [hi]

[2] Демонстрация области действия $private: в 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

То есть приватный $var был виден только непосредственно внутри внешнего { ... };вложенный { ... } снова увидел область видимости прародителя $var.

...