Bi karanîna PowerShell û WSL-ê emrên Linux-ê di Windows-ê de entegre kirin

Pirsek tîpîk ji pêşdebirên Windows: "Çima hîn tune ye <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>?. Ma ew şûştinek hêzdar e less an amûrên nas grep an sed, Pêşdebirên Windows-ê dixwazin bi hêsanî bigihîjin van fermanan di xebata xwe ya rojane de.

Pergala Windows-ê ji bo Linux (WSL) di vî warî de gaveke mezin avêtiye. Ew dihêle hûn bi proxykirina wan ji Windows-ê emrên Linux-ê bang bikin wsl.exe (mînak, wsl ls). Her çend ev pêşkeftinek girîng e jî, ev vebijark ji gelek kêmasiyan dikişîne.

  • Zêdekirina Ubiquitous wsl bêzar û nexwezayî.
  • Riyên Windows-ê di argumanan de her gav naxebitin ji ber ku paşkêşkêşan ji bilî veqetankerên pelrêça wekî karakterên revê têne şîrove kirin.
  • Riyên Windows-ê di argumanan de ji bo xala çiyê ya têkildar di WSL-ê de nayên wergerandin.
  • Mîhengên xwerû di profîlên WSL yên bi nav û guhêrbarên hawîrdorê de rêz nayê girtin.
  • Temamkirina riya Linux nayê piştgirî kirin.
  • Temamkirina fermanê nayê piştgirî kirin.
  • Temamkirina arguman nayê piştgirî kirin.

Wekî encamek, emrên Linux di bin Windows-ê de wekî hemwelatiyên çîna duyemîn têne derman kirin - û karanîna wan ji fermanên xwemalî dijwartir e. Ji bo wekhevkirina mafên wan, pêwîstî bi çareserkirina pirsgirêkên rêzkirî heye.

Wrapperên fonksiyonê PowerShell

Bi pêlên fonksiyonên PowerShell re, em dikarin temamkirina fermanê zêde bikin û hewcedariya pêşgiran ji holê rakin wsl, riyên Windows-ê di rêyên WSL de werdigerîne. Pêdiviyên bingehîn ji bo şêlan:

  • Ji bo her emrê Linuxê divê yek pêça fonksiyonê bi heman navî hebe.
  • Pêdivî ye ku şêl rêyên Windows-ê yên ku wekî arguman hatine derbas kirin nas bike û wan veguherîne rêyên WSL.
  • Divê şêl bang bike wsl bi fermana Linuxê ya guncaw ji her têketina boriyê re û derbaskirina her argumanên rêza fermanê derbasî fonksiyonê dibe.

Ji ber ku ev şêwaz dikare li her fermanê were sepandin, em dikarin pênaseya van pêçanan jêbirin û wan bi dînamîkî ji navnîşek fermanên ku têne import kirin biafirînin.

# 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 ' ')
    }
}
"@
}

Lîsteya $command fermanên import diyar dike. Dûv re em ji bo her yek ji wan bi karanîna fermanê bi dînamîkî pêçek fonksiyonek diafirînin Invoke-Expression (bi yekem jêbirina navên ku dê bi fonksiyonê re nakokî werin rakirin).

Fonksîyon li ser argumanên rêzika fermanê dubare dike, bi karanîna fermanan rêyên Windows-ê destnîşan dike Split-Path и Test-Pathû dûv re van rêyan vediguherîne rêyên WSL. Em riyan bi fonksiyonek alîkar dimeşînin Format-WslArgument, ku em ê paşê diyar bikin. Ew ji karakterên taybetî yên wekî valahî û parantezê ku wekî din dê xelet werin şîrove kirin direve.

Di dawiyê de, em radigihînin wsl têketina boriyê û her argumanên xeta fermanê.

Bi van pêçanan hûn dikarin fermanên Linux-ê yên bijare bi rengek xwezayîtir bang bikin bêyî ku pêşgirek lê zêde bikin wsl û bêyî xema ka rê çawa têne guheztin:

  • man bash
  • less -i $profile.CurrentUserAllHosts
  • ls -Al C:Windows | less
  • grep -Ein error *.log
  • tail -f *.log

Koma bingehîn a fermanan li vir tê xuyang kirin, lê hûn dikarin ji bo her fermanek Linux-ê bi tenê lê zêdekirina wê li navnîşê şêlekek biafirînin. Ger hûn vê kodê li xwe zêde bikin profîl PowerShell, ev ferman dê di her danişîna PowerShell de, mîna fermanên xwemalî, ji we re peyda bibin!

Mîhengên Bingehîn

Di Linux-ê de, bi gelemperî di profîlên têketinê de nav û/an guhêrbarên hawîrdorê diyar dikin, ji bo emrên pir caran têne bikar anîn parametreyên xwerû destnîşan dikin (mînak, alias ls=ls -AFh an export LESS=-i). Yek ji dezawantajên proxykirina bi şêlek ne-înteraktîf wsl.exe - ku profîl nehatine barkirin, ji ber vê yekê ev vebijark ji hêla xwerû ve tune ne (ango. ls li WSL û wsl ls dê bi navên ku li jor hatine destnîşan kirin cûda tevbigere).

PowerShell peyda dike $PSDefaultParameterValues, mekanîzmayek standard ji bo diyarkirina pîvanên xwerû, lê tenê ji bo cmdlet û fonksiyonên pêşkeftî. Bê guman, em dikarin ji şêlên xwe fonksiyonên pêşkeftî çêbikin, lê ev tevliheviyên nehewce derdixe holê (mînak, PowerShell navên parameterên qismî têkildar dike (mînak, -a re têkildar e -ArgumentList), ku dê bi fermanên Linux-ê re ku navên qismî wekî arguman digirin nakok bike), û hevoksaziya ji bo danasîna pêşnumayan dê ne ya herî guncaw be (danasîna argumanên xwerû navê parametreyê di mifteyê de hewce dike, ne tenê navê fermanê).

Lêbelê, bi guheztinek sivik a li şêlên me, em dikarin modelek mîna wê bicîh bikin $PSDefaultParameterValues, û vebijarkên xwerû ji bo fermanên Linux çalak bikin!

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 ' ')
    }
}

Derbasbûn $WslDefaultParameterValues ji rêzika fermanê re, em bi rê ve parametreyan dişînin wsl.exe. Ya jêrîn destnîşan dike ka meriv çawa rêwerzan li profîla xweya PowerShell zêde dike da ku mîhengên xwerû mîheng bike. Niha em dikarin wê bikin!

$WslDefaultParameterValues["grep"] = "-E"
$WslDefaultParameterValues["less"] = "-i"
$WslDefaultParameterValues["ls"] = "-AFh --group-directories-first"

Ji ber ku parametre piştî modela $PSDefaultParameterValues, Hûn dikarin neçalakkirina wan hêsan e demkî bi sazkirina mifteyê "Disabled" nav wateyê de $true. Feydeyek zêde ya tabloyek hash-a veqetandî şiyana neçalakkirinê ye $WslDefaultParameterValues cuda ji $PSDefaultParameterValues.

Argument qedandin

PowerShell dihêle hûn bi karanîna fermanê trailerên argumanan tomar bikin Register-ArgumentCompleter. Bash xwedî hêz e Amûrên qedandina otomatîkî yên bernamekirî. WSL dihêle hûn ji PowerShell gazî bash bikin. Ger em karibin temamkirina argumanan ji bo pêçanên fonksiyona PowerShell-ê xwe tomar bikin û ji bo çêkirina temaman gazî bash bikin, em temamkirina argûmanan bi heman rastbûna bash bixwe digirin!

# 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]
    }
}

Koda bêyî têgihîştina hin fonksiyonên hundurîn ên bash hinekî zexm e, lê di bingeh de ya ku em dikin ev e:

  • Tomarkirina temamkerek argumanek ji bo hemî pêçanên fonksiyonên me bi derbaskirina navnîşek $commands di parametreyê de -CommandName bo Register-ArgumentCompleter.
  • Em her fermanê bi fonksiyona şêlê ya ku bash ji bo temamkirina otomatîkî bikar tîne nexşeyê (ji bo destnîşankirina taybetmendiyên temamkirina otomatîkî, bash bikar tîne $F, kurteya ji bo complete -F <FUNCTION>).
  • Veguherandina Argumanên PowerShell $wordToComplete, $commandAst и $cursorPosition nav formata ku ji hêla fonksiyonên xweseriya bash ve li gorî taybetmendiyan tê hêvîkirin oto-temamkirina bernamekirî bash.
  • Em rêzikek fermanê çêdikin ku veguhezînin wsl.exe, ku piştrast dike ku jîngeh bi rêkûpêk hatî saz kirin, fonksiyona temamkirina xweser a guncan bang dike, û encaman bi şêwaza rêz-xet derdixe.
  • Paşê em bang dikin wsl bi rêzika fermanê re, em derketinê bi veqetanerên rêzê veqetînin û ji bo her yekê çêkin CompletionResults, wan birêkûpêk bike û ji karakterên wekî valah û parantezê ku wekî din dê xelet werin şîrove kirin direvin.

Wekî encamek, şêlên fermana meya Linux-ê dê tam heman xweseriya bash bikar bînin! Bo nimûne:

  • ssh -c <TAB> -J <TAB> -m <TAB> -O <TAB> -o <TAB> -Q <TAB> -w <TAB> -b <TAB>

Her oto-temamkirina nirxên taybetî yên argumana berê peyda dike, daneyên mîhengê yên wekî mêvandarên naskirî yên ji WSL dixwîne!

<TAB> dê di nav parametreyan de bizivire. <Ctrl + пробел> dê hemî vebijarkên berdest nîşan bide.

Zêdeyî, ji ber ku me niha xwedan qedandina bash heye, hûn dikarin rêyên Linux-ê rasterast di PowerShell de bixweber temam bikin!

  • less /etc/<TAB>
  • ls /usr/share/<TAB>
  • vim ~/.bash<TAB>

Di rewşên ku temamkirina otomatîkî ya bash ti encamek dernakeve, PowerShell vedigere rêyên Windows-ê yên xwerû yên pergalê. Ji ber vê yekê, di pratîkê de, hûn dikarin di heman demê de her du rê li gorî daxwaza xwe bikar bînin.

encamê

Bi karanîna PowerShell û WSL, em dikarin fermanên Linux-ê wekî serîlêdanên xwemalî di Windows-ê de yek bikin. Ne hewce ye ku hûn li avahîsaziyên Win32 an karûbarên Linux-ê bigerin an jî bi çûna şêlek Linux-ê xebata xwe qut bikin. Adîl WSL saz bikin, mîheng bike Profîla PowerShell и fermanên ku hûn dixwazin têxin navnîş bikin! Xweseriya dewlemend a ji bo parametreyên fermanê yên Linux û Windows û rêyên pelan fonksiyonek e ku îro di fermanên xwemalî yên Windows-ê de jî tune ye.

Koda çavkaniya tevahî ya ku li jor hatî destnîşan kirin, û her weha rêwerzên din ên ji bo tevlêkirina wê di xebata we de heye vir.

Hûn kîjan fermanên Linux-ê herî bikêr dibînin? Dema ku di Windows-ê de dixebitin çi tiştên din ên hevpar winda dibin? Di şîroveyan de binivîsin an li ser GitHub!

Source: www.habr.com

Add a comment