Как вы выполняете произвольную строку внутри скрипта/функции powershell, как если бы строка была фактически введена в скрипт/функцию?

Я не могу заставить свою функцию работать, используя iex (invoke-expression) с переменными. Что я хочу:

function My-Function {

    # code that constructs $command 
    #$command is an arbitrary string that may contain pipes, 
    #variables, command line paramaters, switchs, quoted strings, THE LOT!

    Execute-My-Command-Exactly-As-Though-I-Had-Typed-It-Here $command
}

Например

function My-Function {
    $command = "`$input | select-string hello"

    iex $command
}

Делает ли это (после включения моего файла, содержащего указанную выше функцию)

PS C:\> echo "hello" | My-Function
PS C:\>

Но, очевидно, он должен сделать это:

PS C:\> echo "hello" | My-Function

hello


PS C:\>

Более того, в реальной командной строке переменные ДЕЙСТВИТЕЛЬНО подхватываются iex:

PS C:\> $hello = "hello"
PS C:\>
PS C:\> iex "`$hello | select-string hello"

hello


PS C:\>

Единственный обходной путь, который я могу придумать, - это записать функцию в файл, а затем . включите его, затем позвоните. Но это ужасно! Весь смысл хорошего языка сценариев оболочки в том, что он должен быть в состоянии сделать этот метаматериал простым и легким.

РЕШЕНИЕ:

PowerShell не может этого сделать, хотя latkin дает полезный совет.


person samthebest    schedule 28.08.2012    source источник
comment
Чего именно вы пытаетесь достичь? Почему? Имея немного больше понимания проблемы высокого уровня, которую вы пытаетесь решить, мы, возможно, сможем указать путь к ответу, более похожему на PowerShell. :)   -  person Aaron Jensen    schedule 29.08.2012
comment
В bash, если $command содержит строку скрипта/командной строки, мы можем вызвать ее с помощью строки $command, конечно, в WeakShell это просто выведет $command в виде текста. То, что я хочу, это выполнить-мою-команду-точно-как-хотя-я-напечатал-это-здесь: P   -  person samthebest    schedule 30.08.2012
comment
@samthebest: вызовите другую команду в powershell с оператором вызова: & $command -- вызовите группу команд с блоком сценария (лямбда/анонимная функция): & { cmd1; cmd2 }   -  person x0n    schedule 31.08.2012


Ответы (2)


Я думаю, ты пытаешься бежать раньше, чем можешь ходить. Тем не менее, давайте посмотрим на ваш первый пример выше:

function my-function {
    process {
       $_ | select-string "hello"
    }    
}

"hello" | my-function

Теперь вы можете сказать себе: «Эй, я не об этом спрашивал!» и в связи с этим я предлагаю следующий совет по Invoke-Expression (iex): выполнение произвольного текста, подобного этому, может быть опасным и редко требуется. Как правило, это указывает на отсутствие понимания построения функционально совместимых функций и модулей. Даже одноразовые скрипты редко требуют IEX.

Итак, я не просто оставлю это там, но я не могу разумно ответить на ваш вопрос без точки зрения более высокого уровня на то, что вы пытаетесь сделать. Похоже, вы пытаетесь обобщить какой-то процесс выполнения скрипта или скриптов. Итак, я бы посоветовал изучить различные нативные механизмы для этого в PowerShell, а именно операторы источника (.) и вызова (&).

И, наконец, выпейте кофе и откиньтесь на спинку кресла, чтобы прочитать самую превосходную бесплатную электронную книгу Кита Хилла «Эффективная Windows PowerShell»:

http://rkeithhill.wordpress.com/2009/03/08/efficient-windows-powershell-the-free-ebook/

Первые несколько глав помогут вам помочь себе при изучении правильных способов действий. Он охватывает основные инструменты PowerShell: get-command, get-help, get-member и понимание разницы между режимами command и expression.

person x0n    schedule 28.08.2012
comment
Спасибо за книгу, и да, такие команды, как man и gm, очень полезны (очевидно, и вполовину не так полезны, как их эквиваленты в bash :P). Ваша неприязнь к выполнению произвольного текста обычно указывает на непонимание силы мета-скриптинга. Чем выразительнее язык, тем больше мы можем абстрагировать структуру, что приводит к полностью СУХОМУ коду, который на самом деле безопаснее и проще в отладке. - person samthebest; 29.08.2012
comment
Если вы думаете, что у bash есть эквивалент get-member (gm), то это вы, дорогой сэр, совершенно запутались. Это то, что отличает конвейер на основе объектов от конвейера обработки текста, такого как bash. Думайте о powershell как о bash с автоматическим awk/sed. Конфигурация Windows основана на API; Unix основан на текстовых файлах. Разные инструменты, разные платформы, разные подходы. Вы привыкнете к этому в конце концов. - person x0n; 30.08.2012
comment
Страницы руководства и общие флаги -u (использование), -h (помощь), -i (неинтерактивный), -s (режим сценариев), используемые вместе с общими командами bash, эквивалентны. В bash автоматическая магия происходит во флагах командной строки, хорошее знание команд bash означает, что sed обычно нужно использовать только для обработки фактического текста. Думайте о bash как о powershell с автоматической типизацией, и, следовательно, нет необходимости в жестком ограничивающем конвейере ООП. Рассматривать bash как текст, это все равно, что смотреть на необработанные данные в конвейере PS, а затем запутаться. Со временем привыкнешь ;) - person samthebest; 31.08.2012
comment
лол... Я приветствую ваше творчество. Я сам старый хакер Unix, так что ваши джедайские трюки на мне не сработают ;-) Моим первым ядром был linux 1.2.3. - person x0n; 31.08.2012

$input — это автоматическая переменная очень странного особого случая. Плохая идея вообще полагаться на него, не говоря уже о сочетании с Invoke-Expression. Я предполагаю, что $input находится только в области действия самого тела функции и исчезает в области действия выражения, которое вы вызываете динамически.

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

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

function My-Function{
    & ([scriptblock]::Create('param($newInput); "Newinput is $newInput"')) $input
}

'piped1', 'piped2' |  my-function
person latkin    schedule 28.08.2012
comment
Правда что. Тем не менее, я предвижу, что его следующей проблемой станет непонимание того, что одинарные кавычки необходимы для предотвращения расширения переменной параметра $newInput. Даже простые примеры не так просты для абсолютного новичка. - person x0n; 29.08.2012
comment
Спасибо, это действительно полезно, почти то, что я хотел, и я думаю, настолько близко, насколько позволит WeakShell. Будет мучительно объявлять и передавать переменные, но я могу легко заставить препроцессор сделать это. Да, кажется, что правила области видимости VerboseShell - одна из его ловушек. - person samthebest; 30.08.2012
comment
Эм... слабак? многословный? Я вижу, вы очень стараетесь защитить свою неспособность или нежелание на самом деле узнать что-то новое. Отличная работа. Вместо того, чтобы стонать, как Windows != Unix или PS != bash, будьте внимательны в классе. Вы будете лучшим человеком для этого. - person x0n; 31.08.2012
comment
Ad hominem. Я просто весело говорю, что это слабо и многословно, потому что я верю, что это правда! В этой ветке представлен один из тысяч примеров того, что PS просто не может сделать, а bash может. Вместо того, чтобы пытаться читать мои мысли и придумывать аргументы, будьте внимательны в классе. Вы будете лучшим человеком для этого. - person samthebest; 31.08.2012
comment
Вы думаете, что powershell более многословен, чем bash? Теперь я все слышал. - person x0n; 31.08.2012