Каковы некоторые из наиболее полезных, но малоизвестных функций на языке PowerShell
В то время как я читал о назначениях с несколькими переменными в PowerShell. Это позволяет вам делать что-то вроде этого
64 > $a,$b,$c,$d = "A four word string".split()
65 > $a
A
66 > $b
four
Или вы можете менять переменные в одном выражении
$a,$b = $b,$a
Какие малоизвестные самородки PowerShell вы сталкиваетесь с тем, что, по вашему мнению, не так хорошо известны, как должны быть?
Ответы
Ответ 1
Команда $$
. Мне часто приходится выполнять повторные операции по одному и тому же пути к файлу. Например, проверьте файл, а затем откройте его в VIM. Функция $$
делает этот тривиальный
PS> tf edit some\really\long\file\path.cpp
PS> gvim $$
Это короткий и простой, но это экономит много времени.
Ответ 2
Самой мощной особенностью PowerShell является поддержка ScriptBlock. Тот факт, что вы можете так кратко передать то, что эффективно анонимные методы без каких-либо ограничений типа, столь же мощно, как и указатели на функции С++, и такие же простые, как С# или F # lambdas.
Я имею в виду, насколько здорово, что с помощью ScriptBlocks вы можете реализовать оператор "using" (который PowerShell не имеет по своей сути). Или, pre-v2, вы даже можете реализовать try-catch-finally.
function Using([Object]$Resource,[ScriptBlock]$Script) {
try {
&$Script
}
finally {
if ($Resource -is [IDisposable]) { $Resource.Dispose() }
}
}
Using ($File = [IO.File]::CreateText("$PWD\blah.txt")) {
$File.WriteLine(...)
}
Как здорово это!
Ответ 3
Функция, которую я нахожу, часто упускается из виду - это возможность передать файл в оператор switch.
Переключатель будет перебирать строки и сопоставлять строки (или регулярные выражения с параметром -regex), содержимое переменных, чисел или строки может быть передано в выражение, которое будет оцениваться как $true или $false
switch -file 'C:\test.txt'
{
'sometext' {Do-Something}
$pwd {Do-SomethingElse}
42 {Write-Host "That the answer."}
{Test-Path $_} {Do-AThirdThing}
default {'Nothing else matched'}
}
Ответ 4
$OFS - разделитель полей вывода. Удобный способ указать, как элементы массива разделяются при визуализации в строку:
PS> $OFS = ', '
PS> "$(1..5)"
1, 2, 3, 4, 5
PS> $OFS = ';'
PS> "$(1..5)"
1;2;3;4;5
PS> $OFS = $null # set back to default
PS> "$(1..5)"
1 2 3 4 5
Всегда гарантируя, что вы получите результат массива. Рассмотрим этот код:
PS> $files = dir *.iMayNotExist
PS> $files.length
$файлы в этом случае могут быть $null, скалярным значением или массивом значений. $files.length не даст вам количество файлов, найденных для $null или для одного файла. В случае с одним файлом вы получите размер файла! Всякий раз, когда я не уверен, сколько данных я верну, я всегда добавляю команду в подвыражение массива так:
PS> $files = @(dir *.iMayNotExist)
PS> $files.length # always returns number of files in array
Тогда $files всегда будет массивом. Он может быть пустым или содержать только один элемент, но он будет массивом. Это делает рассуждение с результатом намного проще.
Поддержка ковариации массива:
PS> $arr = '127.0.0.1','192.168.1.100','192.168.1.101'
PS> $ips = [system.net.ipaddress[]]$arr
PS> $ips | ft IPAddressToString, AddressFamily -auto
IPAddressToString AddressFamily
----------------- -------------
127.0.0.1 InterNetwork
192.168.1.100 InterNetwork
192.168.1.101 InterNetwork
Сравнение массивов с использованием Compare-Object:
PS> $preamble = [System.Text.Encoding]::UTF8.GetPreamble()
PS> $preamble | foreach {"0x{0:X2}" -f $_}
0xEF
0xBB
0xBF
PS> $fileHeader = Get-Content Utf8File.txt -Enc byte -Total 3
PS> $fileheader | foreach {"0x{0:X2}" -f $_}
0xEF
0xBB
0xBF
PS> @(Compare-Object $preamble $fileHeader -sync 0).Length -eq 0
True
Чтобы найти больше таких вещей, посмотрите мою бесплатную электронную книгу - Эффективный PowerShell.
Ответ 5
Вдоль строк назначений с несколькими переменными.
$list = 1,2,3,4
Пока ($ list) {
$ head, $list = $list
$ Голова
}
1
2
3
4
Ответ 6
Я использовал это:
if (!$?) { # if previous command was not successful
Do some stuff
}
и я также довольно часто использую $_ (текущий объект конвейера), но они могут быть более известны, чем другие.
Ответ 7
Тот факт, что многие операторы также работают с массивами и возвращают элементы, где сравнение истинно или работает на каждом элементе массива независимо:
1..1000 -lt 800 -gt 400 -like "?[5-9]0" -replace 0 -as "int[]" -as "char[]" -notmatch "\d"
Это быстрее, чем Where-Object
.
Ответ 8
Не функция языка, но очень полезная
f8
- принимает текст, который вы уже ввели, и ищет команду, начинающуюся с этого текста.
Ответ 9
Вкладка - поиск по вашей истории с помощью #
Пример:
PS > Проводник Get-Process
PS > "Ford Explorer"
PS > "Магеллан" | Добавить контент "great explorers.txt"
PS > тип "great explorers.txt"
PS > #expl < - Хит <tab> ключ для циклического перехода через записи истории, которые имеют термин "expl"
Ответ 10
Люблю эту ветку. Я мог бы перечислить массу вещей после прочтения Windows Powershell в действии. Есть разрыв между этой книгой и документацией. Я на самом деле пытался перечислить их всех где-то еще здесь, но был отложен из-за "не вопрос".
Я начну с foreach с трех блоков скриптов (начало/процесс/конец):
Get-ChildItem | ForEach-Object {$sum=0} {$sum++} {$sum}
Говоря об обмене двумя переменными, здесь происходит обмен двух файлов:
${c:file1.txt},${c:file2.txt} = ${c:file2.txt},${c:file1.txt}
Поиск и замена файла:
${c:file.txt} = ${c:file.txt} -replace 'oldstring','newstring'
Использование сборки и использование операторов пространства имен:
using assembly System.Windows.Forms
using namespace System.Windows.Forms
[messagebox]::show('hello world')
Укороченная версия foreach со свойствами и методами
ps | foreach name
'hi.there' | Foreach Split .
Используйте оператор $() вне строк, чтобы объединить два оператора:
$( echo hi; echo there ) | measure
get- content/Set-content с переменными:
$a = ''
get-content variable:a | set-content -value there
Анонимные функции:
1..5 | & {process{$_ * 2}}
Дайте анонимной функции имя:
$function:timestwo = {process{$_ * 2}}
Анонимная функция с параметрами:
& {param($x,$y) $x+$y} 2 5
Вы можете выполнять потоковую передачу из foreach() с помощью этих функций, где обычно вы не можете:
& { foreach ($i in 1..10) {$i; sleep 1} } | out-gridview
Запускать процессы в фоновом режиме, например unix '& amp;', а затем ждать их:
$a = start-process -NoNewWindow powershell {timeout 10; 'done a'} -PassThru
$b = start-process -NoNewWindow powershell {timeout 10; 'done b'} -PassThru
$c = start-process -NoNewWindow powershell {timeout 10; 'done c'} -PassThru
$a,$b,$c | wait-process
Или foreach -parallel в рабочих процессах:
workflow work {
foreach -parallel ($i in 1..3) {
sleep 5
"$i done"
}
}
work
Или параллельный блок рабочего процесса, в котором можно запускать разные вещи:
function sleepfor($time) { sleep $time; "sleepfor $time done"}
workflow work {
parallel {
sleepfor 3
sleepfor 2
sleepfor 1
}
'hi'
}
work
Три параллельные команды в еще трех пространствах выполнения с API:
$a = [PowerShell]::Create().AddScript{sleep 5;'a done'}
$b = [PowerShell]::Create().AddScript{sleep 5;'b done'}
$c = [PowerShell]::Create().AddScript{sleep 5;'c done'}
$r1,$r2,$r3 = ($a,$b,$c).begininvoke()
$a.EndInvoke($r1); $b.EndInvoke($r2); $c.EndInvoke($r3) # wait
($a,$b,$c).Streams.Error # check for errors
($a,$b,$c).dispose() # cleanup
Параллельные процессы с invoke-command, но вы должны иметь повышенные права при работе удаленного PowerShell:
invoke-command localhost,localhost,localhost { sleep 5; 'hi' }
Присвоение - это выражение:
if ($a = 1) { $a }
$a = $b = 2
Получить последний элемент массива с помощью -1:
(1,2,3)[-1]
Отменить вывод с помощью [void]:
[void] (echo discard me)
Включите массивы и $ _ с обеих сторон:
switch(1,2,3,4,5,6) {
{$_ % 2} {"Odd $_"; continue}
4 {'FOUR'}
default {"Even $_"}
}
Получить и установить переменные в модуле:
'$script:count = 0
$script:increment = 1
function Get-Count { return $script:count += $increment }' > counter.psm1 # creating file
import-module .\counter.psm1
$m = get-module counter
& $m Get-Variable count
& $m Set-Variable count 33
См. определение функции модуля:
& $m Get-Item function:Get-Count | foreach definition
Запустить команду с объектом commandinfo и оператором вызова:
$d = get-command get-date
& $d
Динамические модули:
$m = New-Module {
function foo {"In foo x is $x"}
$x=2
Export-ModuleMember -func foo -var x
}
flags enum:
[flags()] enum bits {one = 1; two = 2; three = 4; four = 8; five = 16}
[bits]31
Малоизвестные коды для оператора -replace:
$number Substitutes the last submatch matched by group number.
${name} Substitutes the last submatch matched by a named capture of the form (?).
$$ Substitutes a single "$" literal.
$& Substitutes a copy of the entire match itself.
$' Substitutes all the text from the argument string before the matching portion.
$' Substitutes all the text of the argument string after the matching portion.
$+ Substitutes the last submatch captured.
$_ Substitutes the entire argument string.
Демонстрация рабочих процессов, переживающих прерывания с использованием контрольных точек. Убейте окно или перезагрузите компьютер. Затем снова запустите PS. Используйте get- job и resume-job, чтобы возобновить работу.
workflow test1 {
foreach ($b in 1..1000) {
$b
Checkpoint-Workflow
}
}
test1 -AsJob -JobName bootjob
Режим редактирования Emacs. Нажатие на вкладку завершения перечисляет все опции одновременно. Очень полезно.
Set-PSReadLineOption -EditMode Emacs
Любую команду, которая начинается с "get-", вы можете опустить "get-":
date
help
Завершить анализ --%
и завершить параметры операторов --
.
write-output --% -inputobject
write-output -- -inputobject
Завершение табуляции в подстановочных знаках:
cd \pro*iles # press tab
Скомпилируйте и импортируйте модуль С# с командлетом внутри, даже в Osx:
Add-Type -Path ExampleModule.cs -OutputAssembly ExampleModule.dll
Import-Module ./ExampleModule.dll
Ответ 11
Выполните итерацию в обратном порядке по последовательности, просто используйте len
последовательности с 1 на другой стороне диапазона:
foreach( x in seq.length..1) { Do-Something seq[x] }