Comments 21
Без понтов и зашкаливающего эго.
Стоит, наверное, отметить, что массив object[]
можно скастовать к конкретному типу, например, int[]
, если каждый элемент можно преобразовать.
А еще PowerShell настолько интегрирован с dotnet
, что одних массивов может быть недостаточно. Можно дергать и другие коллекции:
> $coll = [System.Collections.Generic.List[int]]::New()
> $coll.Add(5)
> $coll
> 5
Или даже так:
> [System.Linq.Enumerable]::Range(0, 10).Select([System.Func[int, int]]{param($x) $x * $x}) | Join-string -Sep ", "
> 0, 1, 4, 9, 16, 25, 36, 49, 64, 81
[System.Linq.Enumerable]::Range(0, 10).Select([System.Func[int, int]]{param($x) $x * $x}) Сбой вызова метода из-за отсутствия в [System.Int32] метода с именем "Select".
строка:1 знак:1
+ ([System.Linq.Enumerable]::Range(0, 10)).Select([System.Func[int, int ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Хм, интересно. Ответ оказывается простым.
Я тестировал это в PowerShell Core 7.0-rc3 (stable-версия вроде только что вышла)
В обычном PowerShell это действительно разваливается.
В full-framework тип RangeIterator
, который возвращается этим методом, имеет буквально несколько определенных методов. Проверить легко: запустите интерпретатор csi.exe.
и выполните код:
System.Linq.Enumerable.Range(0, 1)
.GetType()
.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Select(x => x.Name)
.Aggregate((old, @new) => $"{old}, {@new}")
Я получаю такой вывод:
"Equals, GetHashCode, GetType, ToString"
Теперь то-же самое для dotnet-script
интерпретатора. Вывод следующий:
"Clone, MoveNext, Dispose, Select, ToArray, ToList, GetCount, Skip, Take, TryGetElementAt, TryGetFirst, TryGetLast, get_Current, GetEnumerator, Where, ToString, Equals, GetHashCode, GetType"
Т.е в .net core
у вас определен инстанс-метод
IEnumerable<TResult> RangeIterator.Select<TSource, TResult>(Func<TSource, TResult> selector)
который и вызывается. В full framework такого метода нет и вместо него должен вызываться extension-метод
IEnumerable<TResult> Enumerable.Select<TSource, TResult>(this IEnumerable<TSource> @this, Func<TSource, TResult> selector)
и я полагаю PowerShell такие методы не понимает. Но это можно исправить вот так:
[System.Linq.Enumerable]::Select([System.Linq.Enumerable]::Range(0, 10), [Func[int, string]]{param($x) ($x * $x).ToString()}) -join ", "
В легаси PowerShell позходу и Join-String
нет, но вот это выражение у меня работало и в PSCore 7.0.0-rc3, и в PS 5.1.x.
В Powershell для реализации аналогичной функциональности используется другой механизм, свойственный как раз shell-языкам: конвейер и команды (commandlet), которые принимают коллекции по конвейеру на вход, обрабатывают их элементы (или даже коллекцию целиком, например — сортируют ее) определенным образом и передают результат по конвейеру на выход. Скрипты, если они написаны определенным образом, тоже умеют так работать, в качестве таких команд-фильтров.
Кстати, у Powershell есть в этом отношениии еще одна особенность. На выходе из конвейера наружу результаты выглядят как массив, если их несколько, или как одиночный элемент, если элемент один. Такое поведение удобно для интерактивной работы, но вот написание скриптов, наоборот, затрудняет.
p.s .WaitForExit() не предлагать:)
Некоторые "инсталяторы" распаковывают настоящий инсталятор, запускают его и сразу после этого завершают работу. В с ними-то никакой -Wait и не работает.
Перед именем всегда используется символ $
…
[bool]$test = $true
Так хочется это прокомментировать, что аж зубы сводит.
Но — нельзя.
Как прочитавший который десяток спецификаций разных языков (см.публикации) скажу. Только эго заставило МС заменить вполне приличный c/jscript в системной командной строке
Так вот, для языка комнадной оболочки написание программ (скриптов) — это только одна область примения, и не факт, что самая важная. Другая очень важная область применения такого языка — выдача интерактивных команд, причем часто — не одиночных команд, а их связок: взять выдачу одной команды, передать на вход другой для преобразования и т.д. Причем, часто бывает желательным, чтобы вся связка умещалась на одной строке — чтобы было проще вернуть её из истории (стрелкой вверх, например) и выполнить заново.
Лично мне, например, как системному администратору MS Exchange по основному роду занятий, такие вещи приходится проделывать очень часто.
Поэтому сложные конструкции из нескольких команд — типа набора операторов присваивания, операторов цикла — для интерактивной работы подходят плохо. А в языках командной оболочки для этой цели есть очень удобное средство — конвейер (pipe).
Есть и другие особенности Powershell — как свойственные многим другим языкам командной оболочки, так и уникальные именно для него — которые облегчают именно интерактивное выпонение команд. Надеюсь, авторы этой серии о них расскажут.
1. Длинные команды которые «не хочется» использовать.
Что бы найти нужный процесс, остановить запустить сервис или найти файл я не лезу в PS и т.д. и лично я, ещё не разу не видел, что бы кто то лез в PS, что бы наспех получить информацию от системы. Если единственный способ получить нужные данные, это PS апплет, тогда лезу в PS.
2. Медленный. Первый старт иногда приходится секунд 20 ждать, да даже задержка 3-5 секунд напрягает. Тот же cmd стартует мгновенно всегда. Я понимаю что объектная модель и все такое… но для «интерактивной работы» запуск оболочки должен быть мгновенный. У меня небольшой опыт в скриптописании, но все, что я делал на PS, python и bash, на PS всегда было очень медленно.
3. Риторический вопрос: Почему так поздно взялись за него?
- Длинные команды которые «не хочется» использовать.
Есть автокомплит и алиасы
Медленный. Первый старт иногда приходится секунд 20 ждать, да даже задержка 3-5 секунд напрягает.
Как вы этого добиваетесь? У меня разница в старте между cmd и ps визуально неразличима (и то и другое запускается мгновенно). Вы, наверное, про запуск ISE? Она, да, стартует секунды две. Но вас же никто не заставляет использовать ISE, можете запускать в любом терминале на свой выбор.
Сложно совместить удобство работы в консоли с удобством написания скриптов.
вызов функций в PowerShell может показаться непривычным: аргументы (если они есть) не заключаются в круглые скобки и разделяются пробелами
А я вызываю так и все работает:
MyFunction($myVar)
Просто у вас аргументом функции становится не $myVar
, а ($myVar)
Что такое Windows PowerShell и с чем его едят? Часть 2: введение в язык программирования