Një pyetje tipike nga zhvilluesit Windows: "Pse nuk ka asgjë këtu ende? <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>?. Pavarësisht nëse është një rrëshqitje e fuqishme less ose mjete të njohura grep ose sed, zhvilluesit nën Windows duan qasje të lehtë në këto komanda në punën e tyre të përditshme.
ka bërë një hap të madh përpara në këtë drejtim. Ju lejon të thirrni komanda Linux nga Windows, duke i dërguar ata përmes wsl.exe (p.sh., wsl ls). Edhe pse ky është një përmirësim i rëndësishëm, ky opsion vuan nga një sërë disavantazhesh.
- Shtim i kudondodhur
wsle lodhshme dhe e panatyrshme. - Pyut Windows në argumente nuk funksionojnë gjithmonë sepse backslash-et interpretohen si karaktere escape, jo si ndarës direktorish.
- Pyut Windows në argumente nuk përkthehen në pikën përkatëse të montimit në WSL.
- Cilësimet e parazgjedhura nuk respektohen në profilet WSL me pseudonime dhe ndryshore mjedisore.
- Përfundimi i shtegut nuk mbështetet Linux.
- Përfundimi i komandës nuk mbështetet.
- Përfundimi i argumentit nuk mbështetet.
Si rezultat i ekipit Linux perceptohen nën Windows Ata janë si qytetarë të klasit të dytë—dhe më të vështirë për t’u përdorur sesa ekipet e tyre vendase. Për të barazuar të drejtat e tyre, këto çështje duhen adresuar.
Mbështjellësit e funksionit PowerShell
Me mbështjellëset e funksionit PowerShell, ne mund të shtojmë kompletimin e komandës dhe të eliminojmë nevojën për parashtesa wsl, shtigje transmetimi Windows Në rrugën WSL. Kërkesat themelore për predhat:
- Për secilin ekip Linux Duhet të ketë një mbështjellës funksioni me të njëjtin emër.
- Shell-i duhet të njohë shtigjet Windows, të kaluara si argumente, dhe t'i konvertojnë ato në shtigje WSL.
- Predha duhet të thërrasë
wslme komandën e duhur Linux në çdo hyrje të tubacionit dhe duke kaluar çdo argument të linjës së komandës të kaluar në funksion.
Meqenëse ky model mund të zbatohet për çdo komandë, ne mund të abstragojmë përkufizimin e këtyre mbështjellësve dhe t'i gjenerojmë ato në mënyrë dinamike nga një listë komandash për import.
# The commands to import.
$commands = "awk", "emacs", "grep", "head", "less", "ls", "man", "sed", "seq", "ssh", "tail", "vim"
# Register a function for each command.
$commands | ForEach-Object { Invoke-Expression @"
Remove-Alias $_ -Force -ErrorAction Ignore
function global:$_() {
for (`$i = 0; `$i -lt `$args.Count; `$i++) {
# If a path is absolute with a qualifier (e.g. C:), run it through wslpath to map it to the appropriate mount point.
if (Split-Path `$args[`$i] -IsAbsolute -ErrorAction Ignore) {
`$args[`$i] = Format-WslArgument (wsl.exe wslpath (`$args[`$i] -replace "", "/"))
# If a path is relative, the current working directory will be translated to an appropriate mount point, so just format it.
} elseif (Test-Path `$args[`$i] -ErrorAction Ignore) {
`$args[`$i] = Format-WslArgument (`$args[`$i] -replace "", "/")
}
}
if (`$input.MoveNext()) {
`$input.Reset()
`$input | wsl.exe $_ (`$args -split ' ')
} else {
wsl.exe $_ (`$args -split ' ')
}
}
"@
} Listë $command përcakton komandat e importit. Më pas ne gjenerojmë në mënyrë dinamike një mbështjellës funksioni për secilën prej tyre duke përdorur komandën Invoke-Expression (duke hequr fillimisht çdo pseudonim që do të binte ndesh me funksionin).
Funksioni iteron mbi argumentet e rreshtit të komandës dhe përcakton shtigjet Windows duke përdorur komandat Split-Path и Test-Pathdhe më pas i konverton këto shtigje në shtigje WSL. Ne i drejtojmë shtigjet përmes një funksioni ndihmës Format-WslArgument, të cilin do ta përcaktojmë më vonë. I shpëton karaktereve të veçanta si hapësira dhe kllapa që përndryshe do të keqinterpretoheshin.
Së fundi, ne përcjellim wsl hyrja e tubacionit dhe çdo argument i linjës së komandës.
Me ndihmën e mbështjellësve të tillë mund të telefononi komandat tuaja të preferuara Linux në një mënyrë më natyrale, pa shtuar një parashtesë wsl dhe pa u shqetësuar se si shndërrohen shtigjet:
man bashless -i $profile.CurrentUserAllHostsls -Al C:Windows | lessgrep -Ein error *.logtail -f *.log
Një grup bazë komandash tregohet këtu, por ju mund të krijoni një mbështjellës për çdo komandë. Linux, vetëm duke e shtuar në listë. Nëse e shtoni këtë kod në listën tuaj PowerShell, këto komanda do të jenë të disponueshme për ju në çdo sesion të PowerShell, ashtu si komandat amtare!
Cilësimet e parazgjedhura
В Linux Është e zakonshme të përcaktohen pseudonime dhe/ose variabla mjedisi në profile (profili i hyrjes), duke vendosur parametra të paracaktuar për komandat e përdorura shpesh (për shembull, alias ls=ls -AFh ose export LESS=-i). Një nga disavantazhet e proxying përmes një shell jo-interaktive wsl.exe - që profilet nuk janë të ngarkuara, kështu që këto opsione nuk janë të disponueshme si parazgjedhje (d.m.th. ls në WSL dhe wsl ls do të sillet ndryshe me pseudonimin e përcaktuar më sipër).
PowerShell ofron , një mekanizëm standard për përcaktimin e parametrave të paracaktuar, por vetëm për cmdlet dhe funksione të avancuara. Natyrisht, ne mund të bëjmë funksione të avancuara nga predha tona, por kjo sjell komplikime të panevojshme (për shembull, PowerShell lidh emrat e parametrave të pjesshëm (për shembull, -a lidhet me -ArgumentList), i cili do të bie ndesh me komandat Linux, duke marrë emra të pjesshëm si argumente), dhe sintaksa për përcaktimin e vlerave të paracaktuara nuk do të jetë më e përshtatshme (përcaktimi i argumenteve të paracaktuara kërkon emrin e parametrit në ndërprerës, jo vetëm emrin e komandës).
Megjithatë, me një modifikim të vogël në guaskat tona, ne mund të zbatojmë një model të ngjashëm me $PSDefaultParameterValuesdhe aktivizoni opsionet parazgjedhur për komandat Linux!
function global:$_() {
…
`$defaultArgs = ((`$WslDefaultParameterValues.$_ -split ' '), "")[`$WslDefaultParameterValues.Disabled -eq `$true]
if (`$input.MoveNext()) {
`$input.Reset()
`$input | wsl.exe $_ `$defaultArgs (`$args -split ' ')
} else {
wsl.exe $_ `$defaultArgs (`$args -split ' ')
}
} Duke kaluar $WslDefaultParameterValues në vijën e komandës, ne dërgojmë parametra nëpërmjet wsl.exe. Më poshtë tregon se si të shtoni udhëzime në profilin tuaj PowerShell për të konfiguruar cilësimet e paracaktuara. Tani mund ta bëjmë!
$WslDefaultParameterValues["grep"] = "-E"
$WslDefaultParameterValues["less"] = "-i"
$WslDefaultParameterValues["ls"] = "-AFh --group-directories-first" Meqenëse parametrat janë modeluar pas $PSDefaultParameterValuesmundeni përkohësisht duke instaluar çelësin "Disabled" në kuptim $true. Një përfitim shtesë i një tabele të veçantë hash është aftësia për të çaktivizuar $WslDefaultParameterValues veçmas nga $PSDefaultParameterValues.
Plotësimi i argumentit
PowerShell ju lejon të regjistroni trailerat e argumenteve duke përdorur komandën Register-ArgumentCompleter. Bash ka fuqi . WSL ju lejon të telefononi bash nga PowerShell. Nëse mund të regjistrojmë plotësimet e argumenteve për mbështjellësit tanë të funksionit PowerShell dhe të thërrasim bash për të gjeneruar kompletimet, marrim plotësimin e plotë të argumentit me të njëjtën saktësi si vetë bash!
# Register an ArgumentCompleter that shims bash's programmable completion.
Register-ArgumentCompleter -CommandName $commands -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
# Map the command to the appropriate bash completion function.
$F = switch ($commandAst.CommandElements[0].Value) {
{$_ -in "awk", "grep", "head", "less", "ls", "sed", "seq", "tail"} {
"_longopt"
break
}
"man" {
"_man"
break
}
"ssh" {
"_ssh"
break
}
Default {
"_minimal"
break
}
}
# Populate bash programmable completion variables.
$COMP_LINE = "`"$commandAst`""
$COMP_WORDS = "('$($commandAst.CommandElements.Extent.Text -join "' '")')" -replace "''", "'"
for ($i = 1; $i -lt $commandAst.CommandElements.Count; $i++) {
$extent = $commandAst.CommandElements[$i].Extent
if ($cursorPosition -lt $extent.EndColumnNumber) {
# The cursor is in the middle of a word to complete.
$previousWord = $commandAst.CommandElements[$i - 1].Extent.Text
$COMP_CWORD = $i
break
} elseif ($cursorPosition -eq $extent.EndColumnNumber) {
# The cursor is immediately after the current word.
$previousWord = $extent.Text
$COMP_CWORD = $i + 1
break
} elseif ($cursorPosition -lt $extent.StartColumnNumber) {
# The cursor is within whitespace between the previous and current words.
$previousWord = $commandAst.CommandElements[$i - 1].Extent.Text
$COMP_CWORD = $i
break
} elseif ($i -eq $commandAst.CommandElements.Count - 1 -and $cursorPosition -gt $extent.EndColumnNumber) {
# The cursor is within whitespace at the end of the line.
$previousWord = $extent.Text
$COMP_CWORD = $i + 1
break
}
}
# Repopulate bash programmable completion variables for scenarios like '/mnt/c/Program Files'/<TAB> where <TAB> should continue completing the quoted path.
$currentExtent = $commandAst.CommandElements[$COMP_CWORD].Extent
$previousExtent = $commandAst.CommandElements[$COMP_CWORD - 1].Extent
if ($currentExtent.Text -like "/*" -and $currentExtent.StartColumnNumber -eq $previousExtent.EndColumnNumber) {
$COMP_LINE = $COMP_LINE -replace "$($previousExtent.Text)$($currentExtent.Text)", $wordToComplete
$COMP_WORDS = $COMP_WORDS -replace "$($previousExtent.Text) '$($currentExtent.Text)'", $wordToComplete
$previousWord = $commandAst.CommandElements[$COMP_CWORD - 2].Extent.Text
$COMP_CWORD -= 1
}
# Build the command to pass to WSL.
$command = $commandAst.CommandElements[0].Value
$bashCompletion = ". /usr/share/bash-completion/bash_completion 2> /dev/null"
$commandCompletion = ". /usr/share/bash-completion/completions/$command 2> /dev/null"
$COMPINPUT = "COMP_LINE=$COMP_LINE; COMP_WORDS=$COMP_WORDS; COMP_CWORD=$COMP_CWORD; COMP_POINT=$cursorPosition"
$COMPGEN = "bind `"set completion-ignore-case on`" 2> /dev/null; $F `"$command`" `"$wordToComplete`" `"$previousWord`" 2> /dev/null"
$COMPREPLY = "IFS=`$'n'; echo `"`${COMPREPLY[*]}`""
$commandLine = "$bashCompletion; $commandCompletion; $COMPINPUT; $COMPGEN; $COMPREPLY" -split ' '
# Invoke bash completion and return CompletionResults.
$previousCompletionText = ""
(wsl.exe $commandLine) -split 'n' |
Sort-Object -Unique -CaseSensitive |
ForEach-Object {
if ($wordToComplete -match "(.*=).*") {
$completionText = Format-WslArgument ($Matches[1] + $_) $true
$listItemText = $_
} else {
$completionText = Format-WslArgument $_ $true
$listItemText = $completionText
}
if ($completionText -eq $previousCompletionText) {
# Differentiate completions that differ only by case otherwise PowerShell will view them as duplicate.
$listItemText += ' '
}
$previousCompletionText = $completionText
[System.Management.Automation.CompletionResult]::new($completionText, $listItemText, 'ParameterName', $completionText)
}
}
# Helper function to escape characters in arguments passed to WSL that would otherwise be misinterpreted.
function global:Format-WslArgument([string]$arg, [bool]$interactive) {
if ($interactive -and $arg.Contains(" ")) {
return "'$arg'"
} else {
return ($arg -replace " ", " ") -replace "([()|])", ('$1', '`$1')[$interactive]
}
}Kodi është pak i dendur pa kuptuar disa nga funksionet e brendshme të bash, por në thelb ajo që ne bëjmë është kjo:
- Regjistrimi i një plotësuesi të argumenteve për të gjithë mbështjellësit e funksioneve tona duke kaluar një listë
$commandsnë parametër-CommandNamepërRegister-ArgumentCompleter. - Ne hartojmë secilën komandë me funksionin e guaskës që bash përdor për plotësimin automatik (për të përcaktuar specifikimet e plotësimit automatik, përdor bash
$F, shkurtim përcomplete -F <FUNCTION>). - Konvertimi i argumenteve të PowerShell
$wordToComplete,$commandAstи$cursorPositionnë formatin e pritur nga funksionet e plotësimit automatik të bash sipas specifikimeve bash. - Ne krijojmë një linjë komande për ta transferuar
wsl.exe, i cili siguron që mjedisi është konfiguruar saktë, thërret funksionin e duhur të plotësimit automatik dhe nxjerr rezultatet në mënyrë rresht pas rreshti. - Pastaj ne thërrasim
wslme vijën e komandës, ne ndajmë daljen me ndarës të rreshtave dhe gjenerojmë për secilënCompletionResults, duke i renditur ato dhe duke i shpëtuar karaktereve si hapësira dhe kllapa që përndryshe do të keqinterpretoheshin.
Si rezultat, predhat tona të komandës Linux do të përdorë saktësisht të njëjtën plotësim automatik si në bash! Për shembull:
ssh -c <TAB> -J <TAB> -m <TAB> -O <TAB> -o <TAB> -Q <TAB> -w <TAB> -b <TAB>
Çdo plotësim automatik jep vlera specifike për argumentin e mëparshëm, duke lexuar të dhënat e konfigurimit siç janë hostet e njohur nga WSL!
<TAB> do të qarkullojë nëpër parametra. <Ctrl + пробел> do të shfaqë të gjitha opsionet e disponueshme.
Gjithashtu, meqenëse tani funksionojmë me autocompletion në bash, mund të plotësoni automatikisht shtigjet. Linux direkt në PowerShell!
less /etc/<TAB>ls /usr/share/<TAB>vim ~/.bash<TAB>
Në rastet kur plotësimi automatik i bash nuk jep ndonjë rezultat, PowerShell kthehet në shtigjet e parazgjedhura të sistemit. WindowsKështu, në praktikë, ju mund të përdorni të dy shtigjet njëkohësisht sipas gjykimit tuaj.
Përfundim
Duke përdorur PowerShell dhe WSL ne mund të integrojmë komandat Linux в Windows si aplikacionet vendase. Nuk ka nevojë të kërkoni për versione ose shërbime të Win32 Linux ose ndërprisni rrjedhën e punës duke shkuar te Linux-guaskë. Vetëm , konfiguroni и ! Autoplotësim i pasur për parametrat e komandave dhe shtigjet e skedarëve Linux и Windows — kjo është një funksionalitet që nuk është i disponueshëm as në komandat vendase sot Windows.
Kodi i plotë burimor i përshkruar më sipër, si dhe udhëzime shtesë për përfshirjen e tij në rrjedhën tuaj të punës, është i disponueshëm .
Cilat ekipe? Linux Çfarë e konsideroni më të dobishme? Cilat gjëra të tjera të njohura mungojnë kur punoni në WindowsShkruani në komente ose !
Burimi: www.habr.com
