Почему я не могу использовать $ _ в write-host? - PullRequest
2 голосов
/ 13 апреля 2019

Я пытаюсь передать массив строк в write-host и явно использовать $_ для записи этих строк:

'foo', 'bar', 'baz' | write-host $_

Однако, это не с:

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

Это сообщение об ошибке не имеет смысла для меня, потому что я прекрасно умею писать

'foo', 'bar', 'baz' | write-host

Я бы ожидал, что оба конвейера будут эквивалентны. Видимо, это не так. Так в чем же разница?

Ответы [ 2 ]

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

Я бы ожидал, что оба конвейера будут эквивалентны.

Это не так:

'foo', 'bar', 'baz' | write-host

Это основанный на конвейере эквивалент следующего (эквивалент по конечному эффекту, а не технически):

foreach ($str in 'foo', 'bar', 'baz') { Write-Host -Object $str }

То есть в вашей команде Write-Host получает входные данные из конвейера, который неявно привязывается к его -Object параметр для каждого входного объекта , в силу того, что параметр -Object объявлен как принимающий вход конвейера через атрибут [Parameter(ValueFromPipeline=$true)]


'foo', 'bar', 'baz' | write-host $_

Перед началом конвейерной обработки аргументы - $_ в вашем случае - связаны с параметрами first :

Поскольку $_ не предшествует имя параметра, он связывает позиционно с - подразумеваемым - -Object параметром.

Затем, когда начинается конвейерная обработка, pipe *Параметр 1045 * привязки не находит параметр привязки к конвейеру Write-Host, к которому больше привязываться, учитывая, что единственныйтакой параметр, -Object уже был связан , а именно аргументом $_.

Другими словами: ваша команда по ошибке пытается связатьпараметр -Object дважды ; к сожалению, сообщение об ошибке не совсем ясно дает понять.

Большее значение в том, что с использованием $_ только когда-либо делаетсмысл внутри блока скрипта ({ ... }) , который оценивается для каждого входного объекта .
Вне этого контекста, $_ (или его псевдоним, $PSItem) обычно не имеет значения и не должен использоваться.

Хотя $_ чаще всего используется в блоках сценария, передаваемых в командлеты ForEach-Object и Where-Object, существует другое полезное приложение, чаще всегообычно встречается с командлетом Rename-Item: аргумент блока сценария с задержкой привязки :

# Example: rename *.txt files to *.dat files using a delay-bind script block:
Get-Item *.txt | Rename-Item -NewName { $_.BaseName + '.dat' }

То есть вместо передачи статического нового имени вRename-Item, вы передаете блок скрипта, который оценивается для каждого входного объекта - с указателем входного объектаот d до $_, как обычно - что обеспечивает динамическое поведение.

Как объяснено в связанном ответе, однако, этот метод работает только с параметрами, которые являются (a) привязкой к конвейеру и (b) не [object] или [scriptblock] напечатано;поэтому, учитывая, что Write-Object -Object параметр напечатан [object], метод не работает:

 # Try to enclose all inputs in [...] on output.
 # !! DOES NOT WORK.
 'foo', 'bar', 'baz' | write-host -Object { "[$_]" }

Следовательно, конвейеррешение на основе требует использования ForEach-Object в этом случае:

# -Object is optional
PS> 'foo', 'bar', 'baz' | ForEach-Object { write-host -Object "[$_]" }
[foo]
[bar]
[baz]
0 голосов
/ 13 апреля 2019

Вы можете использовать его, как iRon указано в комментариях. $_ или $PSItem - текущий объект в конвейере, который обрабатывается. Как правило, вы видите это с командами, которые требуют обработки или блока сценария. Вы должны будете содержать команду Write-Host в аналогичном блоке обработки.

'foo', 'bar', 'baz' | ForEach-Object {write-host $_}

Вот пример использования блока процесса функции:

function write-stuff {
    process { write-host $_ }
}

'foo', 'bar', 'baz' | write-stuff
bar
foo
hi
...