Передача строкового массива в функцию powershell не работает должным образом [duplicate]

Другое событие NullPointerException возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals для гарантированного непустого объекта.

Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null.

Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

330
задан George Stocker 26 June 2014 в 17:33
поделиться

14 ответов

Параметры при вызове функций в PowerShell (все версии) разделены пробелами, а не запятыми. Кроме того, скобки полностью не нужны и вызовут ошибку синтаксического анализа в powershell 2.0 (или более поздней), если Set-StrictMode активен. Параметризованные аргументы используются только в .NET-методах.

function foo($a, $b, $c) {
   "a: $a; b: $b; c: $c"
}

ps> foo 1 2 3
a: 1; b: 2; c: 3
440
ответ дан x0n 20 August 2018 в 06:56
поделиться
  • 1
    Я знал, что это я :-) Спасибо. – Nasir 14 February 2011 в 03:08
  • 2
    Самое главное, что, наконец, помогло «закрепить» это в моем сознании, - последнее предложение: «Семантические аргументы используются только в .NET-методах». – Ashley Steel 12 December 2013 в 19:25
  • 3
    Я предпочитаю использовать paranthesis и запятую. Возможно ли это сделать в powershell? – sam yi 19 March 2014 в 06:27
  • 4
    @samyi No. Передача функции (1,2,3) функции эффективно рассматривается как массив; один аргумент. Если вы хотите использовать аргументы стиля метода OO, используйте модули: $m = new-module -ascustomobject { function Add($x,$y) { $x + $y } }; $m.Add(1,1) – x0n 19 March 2014 в 15:18
  • 5
    Powershell ... Просто ДОЛЖЕН БЫТЬ РАЗЛИЧНЫМ ... – Jmoney38 21 October 2016 в 19:56

Я не знаю, что вы делаете с функцией, но посмотрите на использование ключевого слова «param». Это намного более мощно для передачи параметров в функцию и делает ее более удобной для пользователя. Ниже приведена ссылка на слишком сложную статью от Microsoft об этом. Это не так сложно, как в статье. Использование параметра

Также приведен пример из потока на этом сайте:

Проверьте это.

3
ответ дан Community 20 August 2018 в 06:56
поделиться
  • 1
    Спасибо за ответ. Однако при вызове функции у меня возникали проблемы. Не важно, была ли функция объявлена ​​с параметром или без нее. – Nasir 16 February 2011 в 15:08

Если вы попытаетесь:

PS > Test("ABC", "GHI") ("DEF")

, вы получите:

$arg1 value: ABC GHI
$arg2 value: DEF

, чтобы вы увидели, что скобка разделяет параметры

. Если вы попытаетесь:

PS > $var = "C"
PS > Test ("AB" + $var) "DEF"

вы получаете:

$arg1 value: ABC
$arg2 value: DEF

Теперь вы можете найти некоторую непосредственную полезность скобки - пространство не станет разделителем для следующего параметра - вместо этого у вас есть eval.

10
ответ дан Cœur 20 August 2018 в 06:56
поделиться
  • 1
    Parens не разделяет параметры. Они определяют массив. – n0rd 12 October 2013 в 20:16

Если вы не знаете (или не заботитесь) о том, сколько аргументов вы перейдете к функции, вы также можете использовать очень простой подход:

Код:

function FunctionName()
{
    Write-Host $args
}

Это будет печатать все аргументы. Например:

FunctionName a b c 1 2 3

Выход

a b c 1 2 3

Я считаю это особенно полезным при создании функций, которые используют внешние команды, которые могут иметь много разных (и необязательных) параметров, но полагаются на указанную команду для обеспечения обратной связи по синтаксическим ошибкам и т. д.

Вот еще один пример реального мира (создание функции для команды tracert, которую я ненавижу, чтобы помнить усеченное имя);

Код:

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
4
ответ дан Draino 20 August 2018 в 06:56
поделиться

Поскольку это часто просматриваемый вопрос, я хочу упомянуть, что функция PowerShell должна использовать одобренные глаголы (Verb-Noun как имя функции). Также вы можете указать такие параметры, как параметр обязательный и положение параметра:

function Test-Script
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]$arg1,

        [Parameter(Mandatory=$true, Position=1)]
        [string]$arg2
    )

    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Чтобы передать параметр в вы можете либо использовать позицию:

Test-Script "Hello" "World"

Или вы укажите имя параметра:

Test-Script -arg1 "Hello" -arg2 "World"

Вы не используете круглые скобки, например вы делаете, когда вызываете функцию внутри C #.


Я бы рекомендовал always передавать имена параметров при использовании более одного параметра, так как это больше читаемый .

1
ответ дан freshr 20 August 2018 в 06:56
поделиться

Вы также можете передавать параметры в функции.

function FunctionName()
{
    Param ([string]$ParamName);
    #Operations
}
0
ответ дан Kaushal Khamar 20 August 2018 в 06:56
поделиться
  • 1
    Это будет определение параметров для функции, исходный вопрос состоял в том, как указать параметры при вызове функции. – Nasir 15 May 2016 в 22:07

Вы вызываете функции PowerShell без скобок и без использования запятой в качестве разделителя. Попробуйте использовать:

   test "ABC" "DEF"

В PowerShell запятая (,) является оператором массива, например

   $a = "one", "two", "three"

Она устанавливает $ a в массив с тремя значениями.

37
ответ дан Kevin Fegan 20 August 2018 в 06:56
поделиться
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC") ("DEF")
2
ответ дан kleopatra 20 August 2018 в 06:56
поделиться

Правильный ответ уже предоставлен, но этот вопрос кажется достаточно распространенным, чтобы гарантировать некоторые дополнительные детали для тех, кто хочет понять тонкости. Я бы добавил это как комментарий, но я хотел включить иллюстрацию - я потерял это из моей быстрой справочной диаграммы функций PowerShell. Это предполагает, что сигнатура функции f является f($a, $b, $c):

syntax pitfalls of a function call [/g4]

Таким образом, можно вызвать функцию с пространственным разделением positional параметры или независимые от заказа параметры с именем . Другие подводные камни показывают, что вам нужно знать запятые, круглые скобки, и пустое пространство.

Для дальнейшего чтения см. Мою статью Вниз по кроличьей дыре: исследование в Трубопроводы, функции и параметры PowerShell , опубликованные только на Simple-Talk.com. В статье также содержится ссылка на краткую справочную / настенную диаграмму.

211
ответ дан Michael Sorens 20 August 2018 в 06:56
поделиться
  • 1
    Объяснение с более подробным синтаксисом, вызывающим каждый параметр, и присвоение ему значения действительно закрепило его. Спасибо! – ConstantineK 15 December 2013 в 02:28
  • 2
    Спасибо, это заставило меня мысленно не понимать, что я делаю неправильно. Когда я, наконец, сделал все правильно, я проголодался объяснить это поведение. – BSAFH 26 August 2014 в 04:53
  • 3
    большое объяснение! картинка стоит тысячи слов – Andrzej Martyna 4 February 2015 в 11:43
  • 4
    Спасибо, что опубликовали это как ответ. Зная, почему что-то неправильно так же важно, как и то, что неправильно. – PunkyGuy 23 November 2015 в 11:49
  • 5
    Это гораздо лучший ответ. Это должно быть дальше. – Mark Bertenshaw 16 April 2016 в 11:39
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test "ABC" "DEF"
13
ответ дан Rob W 20 August 2018 в 06:56
поделиться

I утверждает следующее ранее:

Общая проблема заключается в использовании сингулярной формы $arg, что неверно. Он должен всегда быть множественным как $args.

Проблема не в этом. Фактически, $arg может быть чем угодно. Проблема заключалась в использовании запятой и скобками. Я запускаю следующий код, который работал, и результат следует:

Код:

Function Test([string]$var1, [string]$var2)
{
    Write-Host "`$var1 value: $var1"
    Write-Host "`$var2 value: $var2"
}

Тест «ABC» «DEF»

Выход:

Значение $ var1: значение ABC $ var2: DEF

1
ответ дан Sébastien 20 August 2018 в 06:56
поделиться
  • 1
    Спасибо, мой друг, однако, вы опаздываете на пару лет :-) В трех лучших ответах здесь достаточно подробно рассмотрены проблемы. Могу ли я предложить перейти в раздел «Без ответа» и попробовать некоторые из этих вопросов? – Nasir 8 November 2013 в 15:49
Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

Это правильное объявление параметров https://technet.microsoft.com/en-us/library/dd347600.aspx

И это действительно работает

1
ответ дан Sergii Kimlik 20 August 2018 в 06:56
поделиться

Некоторые хорошие ответы здесь, но я хотел указать еще пару вещей. Функциональные параметры на самом деле являются местом, где сияет PowerShell. Например, вы можете иметь либо именованные, либо позиционные параметры в таких расширенных функциях:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [int] $Id
    )
}

Тогда вы можете либо вызвать его, указав имя параметра, либо просто использовать позиционные параметры, так как вы явно определили их. Таким образом, любой из них будет работать:

Get-Something -Id 34 -Name "Blah" 
Get-Something "Blah" 34

Первый пример работает, хотя имя предоставляется вторым, потому что мы явно использовали имя параметра. Второй пример работает на основе позиции, поэтому Name должно быть первым. Когда это возможно, я всегда пытаюсь определить позиции, так что доступны обе опции.

PowerShell также имеет возможность определять наборы параметров. Он использует это вместо перегрузки метода и снова весьма полезен:

function Get-Something
{
    [CmdletBinding(DefaultParameterSetName='Name')]
    Param
    (
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
         [int] $Id
    )
}

Теперь функция либо примет имя, либо идентификатор, но не то, и другое. Вы можете использовать их позиционно или по имени. Поскольку они представляют собой другой тип, PowerShell выяснит это. Таким образом, все это будет работать

Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23

. Вы также можете назначить дополнительные параметры для различных наборов параметров. (Очевидно, это был довольно простой пример). Внутри функции вы можете определить, какой набор параметров использовался с свойством $ PsCmdlet.ParameterSetName. Например:

if($PsCmdlet.ParameterSetName -eq "Name")
{
    Write-Host "Doing something with name here"
}

Затем в соответствующей заметке есть также проверка параметров в PowerShell. Это одна из моих любимых функций PowerShell, и она делает код внутри ваших функций очень чистым. Существуют многочисленные проверки, которые вы можете использовать. Пара примеров -

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidatePattern('^Some.*')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [ValidateRange(10,100)]
         [int] $Id
    )
}

. В первом примере ValidatePattern принимает регулярное выражение, которое гарантирует, что предоставленный параметр соответствует ожидаемому. Если это не так, возникает интуитивное исключение, в котором вы точно указываете, что не так. Таким образом, в этом примере «что-то» будет работать нормально, но «лето» не пройдет проверку.

ValidateRange гарантирует, что значение параметра находится между диапазоном, который вы ожидаете от целого. Таким образом, 10 или 99 будут работать, но 101 сделает исключение.

Еще один полезный вариант - ValidateSet, который позволяет явно определить массив допустимых значений. Если что-то еще введено, будет выбрано исключение. Есть и другие, но, вероятно, наиболее полезным является ValidateScript. Для этого требуется блок сценария, который должен оцениваться до $ true, поэтому небо - это предел. Например:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
         [ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
         [string] $Path
    )
}

В этом примере мы уверены не только в том, что $ Path существует, но и в том, что это файл (в отличие от каталога) и имеет расширение .csv. ($ _ относится к параметру, когда внутри вашего скриптового блока.) Вы также можете передавать гораздо большие многострочные блоки сценариев, если требуется этот уровень, или использовать несколько сценариев, подобных мне. Это чрезвычайно полезно и обеспечивает отличные чистые функции и интуитивные исключения.

14
ответ дан wonea 20 August 2018 в 06:56
поделиться
  • 1
    +1 для демонстрации стиля вызова функции My_Function -NamedParamater "ParamValue". Это шаблон, который требует больше кода сценария PS для удобочитаемости. – Mister_Tom 22 November 2017 в 20:46
10
ответ дан CÅ“ur 31 October 2018 в 06:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: