Ṣiṣepọ awọn pipaṣẹ Linux sinu Windows nipa lilo PowerShell ati WSL

Ibeere aṣoju lati ọdọ awọn olupilẹṣẹ Windows: “Kini idi ti ko si <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>? Boya o jẹ rọra ti o lagbara less tabi faramọ irinṣẹ grep tabi sed, Awọn olupilẹṣẹ Windows fẹ iraye si irọrun si awọn aṣẹ wọnyi ni iṣẹ ojoojumọ wọn.

Windows Subsystem fun Lainos (WSL) ti ṣe igbesẹ nla siwaju ni ọran yii. O gba ọ laaye lati pe awọn aṣẹ Linux lati Windows nipa sisọ wọn nipasẹ wsl.exe (fun apẹẹrẹ, wsl ls). Botilẹjẹpe eyi jẹ ilọsiwaju pataki, aṣayan yii jiya lati ọpọlọpọ awọn alailanfani.

  • Afikun ibigbogbo wsl tedious ati atubotan.
  • Awọn ọna Windows ni awọn ariyanjiyan ko ṣiṣẹ nigbagbogbo nitori awọn ifasilẹyin jẹ itumọ bi awọn kikọ abayo kuku ju awọn oluyapa ilana.
  • Awọn ọna Windows ni awọn ariyanjiyan ko tumọ si aaye oke ti o baamu ni WSL.
  • Awọn eto aiyipada ko ni ibọwọ ninu awọn profaili WSL pẹlu inagijẹ ati awọn oniyipada ayika.
  • Ipari ọna Linux ko ni atilẹyin.
  • Ipari aṣẹ ko ni atilẹyin.
  • Ipari ariyanjiyan ko ni atilẹyin.

Bi abajade, awọn aṣẹ Linux ni a tọju bi awọn ara ilu keji labẹ Windows-ati pe o nira pupọ lati lo ju awọn aṣẹ abinibi lọ. Lati ṣe deede awọn ẹtọ wọn, o jẹ dandan lati yanju awọn iṣoro ti a ṣe akojọ.

Awọn murasilẹ iṣẹ PowerShell

Pẹlu awọn murasilẹ iṣẹ PowerShell, a le ṣafikun ipari aṣẹ ati imukuro iwulo fun awọn asọtẹlẹ wsl, titumọ awọn ọna Windows si awọn ọna WSL. Awọn ibeere ipilẹ fun awọn ikarahun:

  • Fun gbogbo aṣẹ Lainos gbọdọ wa ni ipari iṣẹ kan pẹlu orukọ kanna.
  • Ikarahun naa gbọdọ ṣe idanimọ awọn ọna Windows ti o kọja bi awọn ariyanjiyan ati yi wọn pada si awọn ọna WSL.
  • Ikarahun yẹ ki o pe wsl pẹlu aṣẹ Linux ti o yẹ si titẹ sii opo gigun ti epo ati gbigbe eyikeyi awọn ariyanjiyan laini aṣẹ kọja si iṣẹ naa.

Niwọn bi o ti jẹ pe apẹẹrẹ yii le lo si eyikeyi aṣẹ, a le ṣe alaye asọye ti awọn murasilẹ wọnyi ki o ṣe ina wọn ni agbara lati atokọ ti awọn aṣẹ lati gbe wọle.

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

akojọ $command asọye gbe wọle ase. Lẹhinna a ṣe ina-itumọ ti iṣelọpọ iṣẹ fun ọkọọkan wọn nipa lilo aṣẹ naa Invoke-Expression (nipa akọkọ yiyọ eyikeyi inagijẹ ti yoo rogbodiyan pẹlu awọn iṣẹ).

Iṣẹ naa ṣe atunṣe lori awọn ariyanjiyan laini aṣẹ, pinnu awọn ọna Windows nipa lilo awọn aṣẹ Split-Path и Test-Pathati lẹhinna yi awọn ọna wọnyi pada si awọn ọna WSL. A nṣiṣẹ awọn ọna nipasẹ iṣẹ oluranlọwọ Format-WslArgument, eyi ti a yoo setumo nigbamii. O sa fun awọn ohun kikọ pataki gẹgẹbi awọn alafo ati awọn akọmọ ti yoo jẹ bibẹẹkọ ṣe itumọ.

Ni ipari, a gbejade wsl titẹ sii opo gigun ti epo ati awọn ariyanjiyan laini aṣẹ eyikeyi.

Pẹlu awọn murasilẹ wọnyi o le pe awọn aṣẹ Lainos ayanfẹ rẹ ni ọna adayeba diẹ sii laisi fifi iṣaaju kan kun wsl ati laisi aibalẹ nipa bawo ni awọn ọna ti yipada:

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

Eto ipilẹ ti awọn aṣẹ ti han nibi, ṣugbọn o le ṣẹda ikarahun fun eyikeyi aṣẹ Linux nipa fifi kun si atokọ naa. Ti o ba fi koodu yii kun si rẹ profaili PowerShell, awọn aṣẹ wọnyi yoo wa fun ọ ni gbogbo igba PowerShell, gẹgẹ bi awọn aṣẹ abinibi!

Awọn Eto Aiyipada

Ni Lainos, o wọpọ lati ṣalaye awọn inagijẹ ati/tabi awọn oniyipada ayika ni awọn profaili iwọle, ṣeto awọn aye aiyipada fun awọn aṣẹ ti a lo nigbagbogbo (fun apẹẹrẹ, alias ls=ls -AFh tabi export LESS=-i). Ọkan ninu awọn aila-nfani ti aṣoju nipasẹ ikarahun ti kii ṣe ibaraẹnisọrọ wsl.exe - pe awọn profaili ko kojọpọ, nitorinaa awọn aṣayan wọnyi ko si nipasẹ aiyipada (ie. ls ni WSL ati wsl ls yoo huwa otooto pẹlu inagijẹ asọye loke).

PowerShell pese $PSDefaultParameterValues, ẹrọ boṣewa fun asọye awọn aye aiyipada, ṣugbọn fun awọn cmdlets nikan ati awọn iṣẹ ilọsiwaju. Nitoribẹẹ, a le ṣe awọn iṣẹ ilọsiwaju lati inu awọn ikarahun wa, ṣugbọn eyi ṣafihan awọn ilolu ti ko wulo (fun apẹẹrẹ, PowerShell ni ibamu pẹlu awọn orukọ paramita apakan (fun apẹẹrẹ, -a ni ibamu pẹlu -ArgumentList), eyiti yoo tako pẹlu awọn aṣẹ Linux ti o gba awọn orukọ apakan bi awọn ariyanjiyan), ati sintasi fun asọye awọn iye aiyipada kii yoo jẹ deede julọ (awọn ariyanjiyan aiyipada nilo orukọ paramita ninu bọtini, kii ṣe orukọ aṣẹ nikan) .

Sibẹsibẹ, pẹlu iyipada diẹ si awọn ikarahun wa, a le ṣe imuse awoṣe kan ti o jọra si $PSDefaultParameterValues, ati mu awọn aṣayan aiyipada ṣiṣẹ fun awọn aṣẹ 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 ' ')
    }
}

Ti nkọja lọ $WslDefaultParameterValues si laini aṣẹ, a firanṣẹ awọn paramita nipasẹ wsl.exe. Atẹle yii fihan bi o ṣe le ṣafikun awọn ilana si profaili PowerShell rẹ lati tunto awọn eto aiyipada. Bayi a le ṣe!

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

Niwon awọn paramita ti wa ni awoṣe lẹhin $PSDefaultParameterValues, O le o rọrun lati mu wọn kuro fun igba diẹ nipa fifi bọtini sii "Disabled" sinu itumo $true. Anfaani afikun ti tabili hash lọtọ ni agbara lati mu $WslDefaultParameterValues lọtọ lati $PSDefaultParameterValues.

Ipari ariyanjiyan

PowerShell gba ọ laaye lati forukọsilẹ awọn tirela ariyanjiyan nipa lilo aṣẹ naa Register-ArgumentCompleter. Bash ni agbara siseto laifọwọyi-ipari irinṣẹ. WSL gba ọ laaye lati pe bash lati PowerShell. Ti a ba le forukọsilẹ awọn ipari ariyanjiyan fun awọn ohun elo iṣẹ PowerShell wa ati pe bash lati ṣe agbekalẹ awọn ipari, a gba ipari ariyanjiyan ni kikun pẹlu konge kanna bi bash funrararẹ!

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

Koodu naa jẹ ipon diẹ laisi agbọye diẹ ninu awọn iṣẹ inu bash, ṣugbọn ni ipilẹ ohun ti a ṣe ni eyi:

  • Fiforukọṣilẹ ipari ariyanjiyan fun gbogbo awọn murasilẹ iṣẹ wa nipa gbigbe atokọ kan $commands ni paramita -CommandName fun Register-ArgumentCompleter.
  • A ya aworan aṣẹ kọọkan si iṣẹ ikarahun ti bash nlo fun adaṣe adaṣe (lati ṣalaye awọn pato pipe adaṣe, awọn lilo bash $F, abbreviation fun complete -F <FUNCTION>).
  • Iyipada awọn ariyanjiyan PowerShell $wordToComplete, $commandAst и $cursorPosition sinu ọna kika ti a nireti nipasẹ awọn iṣẹ adaṣe adaṣe bash ni ibamu si awọn pato siseto auto-ipari bash.
  • A ṣajọ laini aṣẹ lati gbe lọ si wsl.exe, eyi ti o ṣe idaniloju pe a ti ṣeto ayika ti o tọ, pe iṣẹ-ṣiṣe-ipari-laifọwọyi ti o yẹ, ati awọn esi ti o wa ni ọna ila-ila-ila.
  • Lẹhinna a pe wsl pẹlu awọn pipaṣẹ ila, a ya awọn o wu nipa ila separators ati ina fun kọọkan CompletionResults, tito wọn ati salọ awọn ohun kikọ gẹgẹbi awọn alafo ati awọn akọmọ ti yoo jẹ bibẹẹkọ ṣe itumọ aiṣedeede.

Bii abajade, awọn ikarahun aṣẹ Linux wa yoo lo adaṣe adaṣe deede bi bash! Fun apere:

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

Ipari adaṣe kọọkan n pese awọn iye ni pato si ariyanjiyan iṣaaju, data iṣeto ni kika gẹgẹbi awọn ọmọ ogun ti a mọ lati WSL!

<TAB> yoo ọmọ nipasẹ awọn paramita. <Ctrl + пробел> yoo fihan gbogbo awọn aṣayan to wa.

Ni afikun, niwọn bi a ti ni adaṣe adaṣe bash, o le ṣe adaṣe awọn ọna Linux taara taara ni PowerShell!

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

Ni awọn ọran nibiti adaṣe adaṣe bash ko ṣe awọn abajade eyikeyi, PowerShell tun pada si awọn ọna Windows aiyipada eto. Nitorinaa, ni iṣe, o le lo awọn ọna mejeeji nigbakanna ni lakaye rẹ.

ipari

Lilo PowerShell ati WSL, a le ṣepọ awọn aṣẹ Linux sinu Windows gẹgẹbi awọn ohun elo abinibi. Ko si iwulo lati wa awọn ile-iṣẹ Win32 tabi awọn ohun elo Linux tabi da gbigbi iṣan-iṣẹ rẹ ṣiṣẹ nipa lilọ si ikarahun Linux kan. O kan fi sori ẹrọ WSL, tunto Profaili PowerShell и ṣe akojọ awọn aṣẹ ti o fẹ gbe wọle! Aṣeṣe adaṣe ọlọrọ fun Linux ati awọn paramita aṣẹ Windows ati awọn ọna faili jẹ iṣẹ ṣiṣe ti ko paapaa wa ni awọn aṣẹ Windows abinibi loni.

Koodu orisun ni kikun ti a ṣalaye loke, bakanna bi awọn itọnisọna afikun fun ṣiṣakopọ rẹ sinu ṣiṣiṣẹsẹhin iṣẹ rẹ, wa nibi.

Awọn ofin Linux wo ni o rii julọ wulo? Kini awọn ohun miiran ti o wọpọ ti nsọnu nigba ṣiṣẹ ni Windows? Kọ ninu awọn comments tabi lori GitHub!

orisun: www.habr.com

Fi ọrọìwòye kun