Egy tipikus kérdés a fejlesztőktől Windows: "Miért nincs itt még semmi? <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>?. Legyen szó erőteljes csúsztatásról less vagy ismerős eszközöket grep vagy sed, fejlesztők alatt Windows könnyen hozzá szeretnének férni ezekhez a parancsokhoz a mindennapi munkájuk során.
hatalmas lépést tett előre ezen a téren. Lehetővé teszi parancsok meghívását Linux A Windows, átirányítva őket wsl.exe (például wsl ls). Bár ez jelentős előrelépés, ennek a lehetőségnek számos hátránya van.
- Mindenütt jelenlévő kiegészítés
wslfárasztó és természetellenes. - Módokon Windows az argumentumokban nem mindig működnek, mert a fordított perjeleket escape karakterként, nem pedig könyvtárelválasztóként értelmezi a rendszer.
- Módokon Windows Az argumentumokban lévő értékek nem kerülnek lefordításra a megfelelő csatolási pontra a WSL-ben.
- Az álneveket és környezeti változókat tartalmazó WSL-profilok nem veszik figyelembe az alapértelmezett beállításokat.
- Az útvonal kiegészítése nem támogatott Linux.
- A parancsok befejezése nem támogatott.
- Az érvelés befejezése nem támogatott.
A csapat eredményeként Linux alatt érzékelik Windows Olyanok, mint a másodrendű állampolgárok – és nehezebben használhatók, mint a hazai csapataik. Ahhoz, hogy egyenlővé tegyük a jogaikat, ezeket a problémákat meg kell oldani.
PowerShell függvényburkolók
A PowerShell függvényburkolók segítségével parancskiegészítést adhatunk hozzá, és kiküszöbölhetjük az előtagok használatát wsl, műsorszórási útvonalak Windows A WSL útvonalon. A héjak alapvető követelményei:
- Minden csapat számára Linux Egyetlen, azonos nevű függvényburkolóval kell rendelkeznie.
- A shellnek fel kell ismernie az útvonalakat Windows, argumentumként adjuk át, és WSL-útvonalakká alakítjuk őket.
- A héjnak hívnia kell
wsla megfelelő paranccsal Linux bármely folyamat bemenetére, és átadja a függvénynek átadott parancssori argumentumokat.
Mivel ez a minta bármely parancsra alkalmazható, elvonatkoztathatjuk ezeknek a burkolóknak a definícióját, és dinamikusan generálhatjuk őket az importálandó parancsok listájából.
# 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 ' ')
}
}
"@
} Lista $command import parancsokat határoz meg. Ezután a parancs segítségével dinamikusan generálunk egy függvényburkolót mindegyikhez Invoke-Expression (először eltávolít minden olyan álnevet, amely ütközik a funkcióval).
A függvény végighalad a parancssori argumentumokon, és meghatározza az elérési utakat. Windows parancsok használatával Split-Path и Test-Pathmajd ezeket az elérési utakat WSL útvonalakká alakítja. Az utakat egy segítő függvényen keresztül vezetjük le Format-WslArgument, amelyet később fogunk meghatározni. Megkerüli a speciális karaktereket, például a szóközöket és a zárójeleket, amelyeket egyébként félreértelmeznének.
Végül közöljük wsl pipeline bemenet és bármely parancssori argumentum.
Az ilyen burkolók segítségével meghívhatod kedvenc parancsaidat Linux természetesebb módon, előtag hozzáadása nélkül wsl és anélkül, hogy aggódnia kellene az útvonalak átalakítása miatt:
man bashless -i $profile.CurrentUserAllHostsls -Al C:Windows | lessgrep -Ein error *.logtail -f *.log
Itt egy alapvető parancskészlet látható, de bármelyik parancshoz létrehozhatsz egy burkolót. Linux, egyszerűen a listához való hozzáadással. Ha hozzáadod ezt a kódot a PowerShell, ezek a parancsok minden PowerShell-munkamenetben elérhetőek lesznek, akárcsak a natív parancsok!
Alapbeállítások
В Linux Gyakori, hogy aliasokat és/vagy környezeti változókat definiálnak a profilokban (bejelentkezési profil), alapértelmezett paramétereket állítva be a gyakran használt parancsokhoz (például alias ls=ls -AFh vagy export LESS=-i). A nem interaktív héjon keresztüli proxyzás egyik hátránya wsl.exe - hogy a profilok nincsenek betöltve, így ezek az opciók alapértelmezés szerint nem érhetők el (pl. ls WSL-ben és wsl ls másként fog viselkedni a fent meghatározott álnévvel).
A PowerShell biztosítja , egy szabványos mechanizmus az alapértelmezett paraméterek meghatározásához, de csak parancsmagokhoz és speciális funkciókhoz. Természetesen készíthetünk speciális függvényeket a héjainkból, de ez szükségtelen bonyodalmakat okoz (például a PowerShell a részleges paraméterneveket korrelálja (pl. -a -vel korrelál -ArgumentList), ami ütközni fog a parancsokkal Linux, részleges neveket veszünk argumentumként), és az alapértelmezett értékek definiálására szolgáló szintaxis nem lesz a legmegfelelőbb (az alapértelmezett argumentumok definiálásához a kapcsolóban lévő paraméter neve szükséges, nem csak a parancs neve).
A héjaink kis módosításával azonban megvalósíthatunk egy hasonló modellt $PSDefaultParameterValues, és engedélyezze a parancsok alapértelmezett beállításait 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 ' ')
}
} Elhaladó $WslDefaultParameterValues a parancssorba a paramétereket keresztül küldjük wsl.exe. Az alábbiakban bemutatjuk, hogyan adhat hozzá utasításokat a PowerShell-profilhoz az alapértelmezett beállítások konfigurálásához. Most megtehetjük!
$WslDefaultParameterValues["grep"] = "-E"
$WslDefaultParameterValues["less"] = "-i"
$WslDefaultParameterValues["ls"] = "-AFh --group-directories-first" Mivel a paraméterek modellezése után $PSDefaultParameterValues, Tudsz ideiglenesen a kulcs telepítésével "Disabled" jelentésbe $true. A különálló hash tábla további előnye a letiltási lehetőség $WslDefaultParameterValues attól külön-külön $PSDefaultParameterValues.
Érvelés befejezése
A PowerShell lehetővé teszi argumentumelőzetesek regisztrálását a paranccsal Register-ArgumentCompleter. Bash erős . A WSL lehetővé teszi a bash meghívását a PowerShellből. Ha a PowerShell függvényburkolóinkhoz regisztrálhatunk argumentumkiegészítéseket, és a bash-t meghívjuk a befejezések generálásához, akkor a teljes argumentumkiegészítést ugyanolyan pontossággal kapjuk meg, mint maga a 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]
}
}A kód egy kicsit sűrű anélkül, hogy megértené a bash néhány belső funkcióját, de alapvetően a következőt tesszük:
- Egy argumentumkiegészítő regisztrálása az összes függvényburkolóhoz egy lista átadásával
$commandsparaméterben-CommandNameaRegister-ArgumentCompleter. - Minden parancsot leképezünk arra a shell függvényre, amelyet a bash az automatikus kiegészítéshez használ (az automatikus kiegészítés specifikációinak meghatározásához, a bash használatához
$F, a rövidítésecomplete -F <FUNCTION>). - PowerShell-argumentumok konvertálása
$wordToComplete,$commandAstи$cursorPositiona bash automatikus kiegészítési funkciói által elvárt formátumba a specifikációknak megfelelően bash. - Összeállítunk egy parancssort az átvitelhez
wsl.exe, amely biztosítja a környezet helyes beállítását, meghívja a megfelelő automatikus kiegészítési függvényt, és soronként adja ki az eredményeket. - Aztán hívjuk
wsla parancssorral sorelválasztókkal választjuk el a kimenetet, és mindegyikhez generáljukCompletionResults, rendezi őket, és kihagyja az olyan karaktereket, mint a szóközök és a zárójelek, amelyeket egyébként félreértelmeznének.
Ennek eredményeként a parancsértelmezőink Linux pontosan ugyanazt az automatikus kiegészítést fogja használni, mint a bash-ban! Például:
ssh -c <TAB> -J <TAB> -m <TAB> -O <TAB> -o <TAB> -Q <TAB> -w <TAB> -b <TAB>
Minden automatikus kiegészítés az előző argumentumra jellemző értékeket ad, és beolvassa a konfigurációs adatokat, például az ismert gazdagépeket a WSL-ből!
<TAB> váltogatja a paramétereket. <Ctrl + пробел> megjeleníti az összes elérhető lehetőséget.
Továbbá, mivel most már működik a bash automatikus kiegészítés, automatikusan kiegészítheted az elérési utakat Linux közvetlenül a PowerShellben!
less /etc/<TAB>ls /usr/share/<TAB>vim ~/.bash<TAB>
Azokban az esetekben, amikor a bash automatikus kiegészítés nem hoz eredményt, a PowerShell visszatér a rendszer alapértelmezett elérési útjaihoz. WindowsÍgy a gyakorlatban mindkét utat egyszerre használhatod, saját belátásod szerint.
Következtetés
A PowerShell és a WSL használatával integrálhatjuk a parancsokat Linux в Windows mint a natív alkalmazások. Nem kell Win32-es buildeket vagy segédprogramokat keresgélni Linux vagy szakítsa meg a munkafolyamatot a következővel: Linux-héj. Csak , Beállítás и Gazdag automatikus kiegészítés parancsparaméterekhez és fájlelérési utakhoz Linux и Windows — ez egy olyan funkció, ami ma még a natív parancsokban sem érhető el Windows.
A fent leírt teljes forráskód, valamint a munkafolyamatba való beépítéséhez további útmutatások elérhetők .
Milyen csapatok? Linux Mit találsz a leghasznosabbnak? Milyen más, ismerős dolgok hiányoznak a munka során WindowsÍrd meg a hozzászólásokban, vagy !
Forrás: will.com
