Разница между ForEach и ForEach-Object в powershell
Есть ли разница между ForEach
и ForEach-Object
?
У меня такой небольшой код, он отлично работает
$txt = Get-Content 'C:\temp\000.txt'
$result = foreach ($line in $txt) {$line.replace(".ini","")}
$result | out-file 'c:\temp\001.txt'
Но если я использую "ForEach-Object", у меня появились ошибки....
$txt = Get-Content 'C:\temp\000.txt'
$result = foreach-object ($line in $txt) {$line.replace(".ini","")}
$result | out-file 'c:\temp\001.txt'
Почему? и как вывести результаты цикла с помощью ForEach-Object
Ответы
Ответ 1
foreach
является псевдонимом ForEach-Object
, но он также является ключевым словом (что запутывает).
Синтаксис foreach ($<item> in $<collection\>){<statement list>}
, который вы используете, это help about_foreach
.
foreach
как ForEach-Object
псевдоним help ForEach-Object
.
Ключевое слово foreach
работает над каждым $<item>
в $<collection>
, как указано в бит ()
.
Псевдоним foreach
/function ForEach-Object
работает над каждым элементом коллекции, который он получает в качестве входного файла.
Ответ 2
Это разные команды для разных целей. В конвейере используется командлет ForEach-Object , и вы используете $PSItem или $_ для ссылки на текущий объект, чтобы запустить {scriptblock} следующим образом:
1..5 | ForEach-Object {$_}
>1
>2
>3
>4
>5
Теперь вы также можете использовать очень похожее ключевое ключевое слово, ForEach, в начале строки. В этом случае вы можете запустить {scriptblock}, в котором вы определяете имя переменной, например:
ForEach ($number in 1..5){$number}
>1
>2
>3
>4
>5
Основное различие здесь заключается в том, где вы используете эту команду: одна используется в середине конвейера, а другая запускает собственный конвейер. В сценариях стиля работы я бы рекомендовал вместо ключевого слова использовать ключевое слово ForEach.
Ответ 3
Оба предыдущих ответа верны, но https://blogs.technet.microsoft.com/heyscriptingguy/2014/07/08/getting-to-know-foreach-and-foreach-object/ имеет хорошее резюме:
Когда вы вводите данные в ForEach, это псевдоним ForEach-Object. Но когда вы помещаете ForEach в начале строки, это оператор Windows PowerShell.
и больше деталей:
Оператор ForEach загружает все элементы заранее в коллекцию, а затем обрабатывает их по одному. ForEach-Object ожидает, что элементы будут передаваться по конвейеру, что снижает требования к памяти, но в то же время снижает производительность.
Затем он включает некоторые измерения производительности и делает вывод:
Так какой из них вы используете? Ну, ответ: "Это зависит". Вы можете перебирать коллекцию элементов с помощью оператора ForEach или командлета ForEach-Object. ForEach идеально подходит, если у вас достаточно памяти, вы хотите добиться максимальной производительности и не заботитесь о передаче вывода другой команде через конвейер. ForEach-Object (с его псевдонимами% и ForEach) принимает данные из конвейера. Хотя процесс обработки выполняется медленнее, он дает вам преимущества блоков Begin, Process и End. Кроме того, он позволяет передавать объекты в другую команду через конвейер. В конце концов, используйте подход, который наилучшим образом соответствует вашим требованиям и возможностям вашей системы.
Ответ 4
Помимо технических отличий, которые были упомянуты ранее, вот некоторые практические отличия для полноты картины (см. Также):
1.) В конвейере вы не знаете общее количество обработанных предметов. Это ситуация, когда вы решили сначала получить полный список, а затем выполнить цикл foreach.
Пример:
$files = gci "c:\fakepath"
$i = 0
foreach ($file in $files) {
$i++
Write-Host "$i / $($files.Count) processed"
}
2.) При существующем списке цикл foreach
работает быстрее, чем версия конвейера, поскольку блок сценария не нужно вызывать каждый раз. (Но разница может быть незначительной в зависимости от выполняемой работы и количества предметов.)
Пример:
$items = 0..100000
Measure-Command { $items | ForEach-Object { $_ } }
# ~500ms on my machine
Measure-Command { foreach ($i in $items) { $i } }
# ~70ms on my machine