Как использовать параметризованный блок скрипта с Where-Object в Powershell? - PullRequest
5 голосов
/ 10 февраля 2011

Есть ли лучший способ передачи информации в блоки сценариев в where-object фильтрах сценариев, чем при использовании родительских переменных?

Справочная информация:

У меня есть сценарий, который ищетпроверенные и / или измененные исходные файлы по сравнению с контролем источника и имеет параметр, который позволяет выполнять более полный поиск.Я использую where-object в нескольких местах с объектом блока сценария, содержащимся в переменной области действия сценария, которую я настраиваю на основе входных параметров сценария.

Итак, если вы попросите провести тщательный поиск, фильтр сравнит файл-кандидат со всеми файлами TFS, чтобы определить, не находится ли файл в системе контроля версий, если вы выберете менее тщательный поиск, фильтрбудет сравниваться только с извлеченными файлами, чтобы увидеть, был ли файл изменен, но не извлечен.

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

Итак, моя проблема в том, что я хотел бы избавиться от глобальной переменной (уровня скрипта) и передать всю необходимую информацию в блоки скрипта в качестве параметров для блоков скрипта.Если бы я использовал invoke-command, я бы использовал параметр ArgumentList для этого.Where-Object, похоже, не имеет этого.Недостатком использования ссылок на переменные родительской области в блоках скрипта является то, что я не могу изменить эти переменные, поэтому я не могу выполнить ленивую инициализацию (или, по крайней мере, я еще не понял, как, не будучи экспертом поОбщие правила для Powershell.)

Ответы [ 3 ]

7 голосов
/ 10 февраля 2011

Просто чтобы немного расширить сказанное Китом, вы можете сделать это так:

ps> $x=2
ps> 1..5 | where (& {param($v); { $_ -eq $v }.getnewclosure() } $x )
2

Я пытался закрыть имплик $args, чтобы сохранить объявление параметра, но $args кажется освобожденным от захвата. Скорее всего, его захватывают, но просто топают.

$x можно легко заменить другим вызовом функции, например (get-x).

По сути, я вызываю скрипт-блок, который возвращает скрипт-блок, который закрывается по внешнему параметру scriptblocks. Реализация та же, что и у Кейта, чуть более лаконична [и тупа.] Лямбдас на победу.

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

-Oisin

5 голосов
/ 10 февраля 2011

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

function FilterProcs([scriptblock]$scriptblock)
{
    Get-Process | Where $scriptblock
}

$name = 'Notepad'

& {
    $name = 'PowerShell'
    FilterProcs {$_.Name -eq $name}.GetNewClosure()
}

$name

В этом случае внутренниймодификация $name видна только локально, а не в области видимости скрипта.Возможно, есть и лучший способ, но я думаю, что это сработает для вас.

Кстати, вот еще один подход, который фильтрует с помощью командлета Foreach-Object:

function FilterProcs([scriptblock]$scriptblock, [object[]]$argumentList)
{
    Get-Process | Foreach {if (&$scriptblock @argumentList){$_}}
}

FilterProcs {param($name, $id) ($_.Name -match $name -and $_.Id -eq $id)} `
            -ArgumentList 'PowerShell_ISE',$pid

PS Приятно видеть, что выподдерживая PowerShellin.: -)

3 голосов
/ 12 февраля 2011

Невозможно закрыть существующий блок скриптов вокруг $ args, но вы можете создать новый блок скриптов с ним:

$x=2
 1..5 | where (& {[scriptblock]::create('$_ -eq ' + $args) } $x )


 2

Как ни странно, создание нового блока скриптов кажется быстрее, чем вызов getnewclosure длясуществующий.Я выполнил оба сценария через 10000 повторений, а создание нового блока сценария с $ args заняло 5,3 секунды, а getnewclosure с объявлением параметра - 7,9.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...