Bashrunner или PowerShell для юниксоида
Какой смысл ограничивать себя чем-то одним, если существует вероятность возникновения задачи непосильной для этого чего-то? Кудряво сказано, а если проще, то есть такая штука, называется кругозор. И потом, какие-то вещи проще познавать на примерах, какие-то в сравнении с чем-то. Но все же лучшим стартом в изучении чего-либо является чтение документации и опыт предшественников, и если первое дает некоторое представление о предмете, второе позволяет избежать повторения ошибок и способствует улучшению решений уже существующих.Причины, согласно которым Bash’исты могут использовать PowerShell (ровно как и наоборот), могут быть самыми разными, но все их мы оставим за кадром. Куда больший интерес представляет то, насколько быстро можно освоить PowerShell юниксоиду. Пожалуй, наиболее удачным было бы такое начало: PS C:\> man man
ИМЯ Get-Help
ОПИСАНИЕ Отображает сведения о командах и концепциях Windows PowerShell.
…
PS C:\> Помимо того, что man в контексте PowerShell является лишь псевдонимом (альясом) командлета Get-Help, языком разметки страницы справочного руководства является xml, в то время как в Bash — это troff, имеющий долгую и увлекательную историю, предшествующую UNIX. Сходство работы man в Bash и PowerShell заканчивается после того, как найдена нужная страница руководства. Далее, в Bash, нужная страница распаковывается, а ее содержимое выводится в терминал, иными словами, запись: $ man proc будет эквивалентна: $ gzip -dc /usr/share/man/man5/proc.5.gz | groff -man -Tascii | less В PowerShell содержимое справки выводится сразу же после считывания данных с диска. Впрочем, эти и многие другие нюансы становятся очевидны по мере изучения как самой справки, так и механизмов заложенных в PowerShell.Наряду с man, в PowerShell есть знакомые каждому юниксоиду ls, cat, echo, history и некоторые другие команды, вывод и функциональные возможности которых продиктованы либо устройством операционной системы, либо логикой самого хоста PowerShell. Но некоторых юниксоидов PowerShell отпугивает потому, что какие-то вещи кажутся неочевидными или избыточными. Например:
$ head foo в PowerShell выглядит так: PS C:\> cat foo | select -f 10 Ничто не мешает определить head самостоятельно. PS C:\> sc function: head {param ([String]$File, [Int32]$Number=10) cat $File | select -f $Number} PS C:\> head foo Если же требуется нечто более продвинутое, следует сперва ознакомиться с такими страницами руководства: PS C:\> man about_function …
PS C:\> Вот вам и страницы руководств в виде простых текстовых файлов, — это лишь к слову.Конечно никто не возбраняет использовать порты юниксовых утилит под Windows, но какой в них смысл, когда можно потратить некоторое время на составление аналогов самосотоятельно, тем самым углубив свои знания в сиснтаксисе, а там глядишь и вовсе станет проще использовать привычные для PowerShell выражения? И все же на первых порах, реализуя некие аналоги, можно добиться некоторой лаконичности, не говоря уже о мастерстве однострочников. Примеры некоторых аналогов представлены ниже.
tail
PS C:\> cat foo | select -l 10 tail -f PS C:\> cat foo -Wait less PS C:\> cat foo | oh -Paging cat -n PS C:\> cat foo | % {$i=0}{$i++;»$i $_»} tr -d PS C:\> »`«test`» -replace [Char]34, '' grep PS C:\> Set-Alias grep Select-String PS C:\> cat foo | grep bar Или: PS C:\> cat foo | ? {$_ -match 'bar'} sed PS C:\> cat foo | % {$_ -replace 'bar', 'foo'} wc PS C:\> (cat foo | measure -Word).Words wc -l PS C:\> (cat foo | measure).Count top PS C:\> while (1){cls; ps; sleep -s 3} which PS C:\> Set-Alias which Get-Command PS C:\> which man whoami PS C:\> ('UserDomainName', 'UserName' | % {[Environment]::$_}) -join '\' time PS C:\> sc function: time {param ($Command) Measure-Command {$Command}} PS C:\> time Get-Help touch PS C:\> Out-File foo -Encoding ASCII touch -a PS C:\> (gi foo).LastAccessTime = [DateTime]'12.31.2014 23:00:00' touch -m PS C:\> (gi foo).LastWriteTime = [DateTime]'12.31.2014 23:00:00' who PS C:\> gp 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*' | >> % {(New-Object Security.Principal.SecurityIdentifier ($_.PSChildName)).Translate ( >> [Security.Principal.NTAccount]).Value} >> … PS C:\> whatis PS C:\> sc function: whatis {param ($Command) (Get-Command $Command).FileVersionInfo.FileDescription} PS C:\> whatis netsh Можно продолжать в таком ключе еще долго, — суть, полагаю, ясна. При этом если у нас имеется более продвинутая реализация некоторой команды, которую планируется использовать довольно часто, можно поместить ее в профиль (man about_Profiles) или же вынести в отдельный модуль (man about_Modules) с каким-нибудь говорящим названием, скажем, bash или unix, или cal, если модуль реализует одноименную команду.cal.psm1
#requires -version 2.0 if (!(Test-Path alias: cal)) {Set-Alias cal Get-Calendar}
function Get-Calendar { param ( [Parameter (Position=0)] [Alias ('m')] [ValidateRange (1, 12)] [Int32]$Month = (Get-Date -u %m), [Parameter (Position=1)] [ValidateRange (2000, 9999)] [Int32]$Year = (Get-Date -u %Y), [Parameter (Position=2)] [Alias ('mf')] [Switch]$MondayFirstly ) begin { [Globalization.DateTimeFormatInfo]:: CurrentInfo.ShortestDayNames | % {$arr = @()}{$arr += $_} $cal = [Globalization.CultureInfo]:: CurrentCulture.Calendar $dow = [Int32]$cal.GetDayOfWeek ([DateTime]([String]$Month + '.1.' + [String]$Year)) if ($MondayFirstly) { $arr = $arr[1…$arr.Length] + $arr[0] if (($doe = --$dow) -lt 0) { $dow = 6 } } } process { $loc = [Globalization.DateTimeFormatInfo]:: CurrentInfo.MonthNames[$Month — 1] + ' ' + $Year $loc = [String]((' ' * [Math]:: Round ((20 — $loc.Length) / 2)) + $loc) if ($dow -ne 0) { for ($i = 0; $i -lt $dow; $i++) { $arr += (' ' * 2) } } 1…$cal.GetDaysInMonth ($Year, $Month) | % { if ($_.ToString ().Length -eq 1) { $arr += ' ' + [String]$_ } else { $arr += [String]$_ } } #foreach } end { Write-Host $loc -fo Magenta for ($i = 0; $i -lt $arr.Length; $i += 6) { Write-Host $arr[$i…($i + 6)] $i++ } '' } }
Export-ModuleMember -Alias cal -Function Get-Calendar После установки модуля: PS C:\> Import-Module cal PS C:\> cal -mf
Апрель 2015 Пн Вт Ср Чт Пт Сб Вс 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
PS C:\> Вот таким вот незатейливым способом можно превратить PowerShell в Bash, а стоит ли оно того — дело сугубо личное.