ืฉื™ืœื•ื‘ ืคืงื•ื“ื•ืช ืœื™ื ื•ืงืก ื‘-Windows ื‘ืืžืฆืขื•ืช PowerShell ื•-WSL

ืฉืืœื” ื˜ื™ืคื•ืกื™ืช ืžืžืคืชื—ื™ Windows: "ืœืžื” ืขื“ื™ื™ืŸ ืื™ืŸ <ะ’ะกะขะะ’ะฌะขะ• ะขะฃะข ะ›ะฎะ‘ะ˜ะœะฃะฎ ะšะžะœะะะ”ะฃ LINUX>?. ื‘ื™ืŸ ืื ืžื“ื•ื‘ืจ ื‘ื”ื—ืœืงื” ื—ื–ืงื” less ืื• ื›ืœื™ื ืžื•ื›ืจื™ื grep ืื• sed, ืžืคืชื—ื™ Windows ืจื•ืฆื™ื ื’ื™ืฉื” ื ื•ื—ื” ืœืคืงื•ื“ื•ืช ืืœื• ื‘ืขื‘ื•ื“ื” ื”ื™ื•ืžื™ื•ืžื™ืช ืฉืœื”ื.

ืžืขืจื›ืช ื”ืžืฉื ื” ืฉืœ Windows ืขื‘ื•ืจ ืœื™ื ื•ืงืก (WSL) ืขืฉื” ืฆืขื“ ืขื ืง ืงื“ื™ืžื” ื‘ื”ืงืฉืจ ื–ื”. ื–ื” ืžืืคืฉืจ ืœืš ืœื”ืชืงืฉืจ ืœืคืงื•ื“ื•ืช ืœื™ื ื•ืงืก ืž-Windows ืขืœ ื™ื“ื™ ื”ืขื‘ืจืช ืื•ืชืŸ ื‘ืืžืฆืขื•ืช proxy wsl.exe (ื“ื•ื’ืžื: wsl ls). ืœืžืจื•ืช ืฉืžื“ื•ื‘ืจ ื‘ืฉื™ืคื•ืจ ืžืฉืžืขื•ืชื™, ืืคืฉืจื•ืช ื–ื• ืกื•ื‘ืœืช ืžืžืกืคืจ ื—ืกืจื•ื ื•ืช.

  • ืชื•ืกืคืช ื‘ื›ืœ ืžืงื•ื wsl ืžื™ื™ื’ืข ื•ืœื ื˜ื‘ืขื™.
  • ื ืชื™ื‘ื™ Windows ื‘ืืจื’ื•ืžื ื˜ื™ื ืœื ืชืžื™ื“ ืขื•ื‘ื“ื™ื ืžื›ื™ื•ื•ืŸ ืฉื”ืœื•ื›ืกื ื™ื ื”ืื—ื•ืจื™ื™ื ืžืชืคืจืฉื™ื ื›ืชื•ื•ื™ ื‘ืจื™ื—ื” ื•ืœื ื›ืžืคืจื™ื“ื™ ืกืคืจื™ื•ืช.
  • ื ืชื™ื‘ื™ Windows ื‘ืืจื’ื•ืžื ื˜ื™ื ืื™ื ื ืžืชื•ืจื’ืžื™ื ืœื ืงื•ื“ืช ื”ื˜ืขื™ื ื” ื”ืžืชืื™ืžื” ื‘-WSL.
  • ื”ื’ื“ืจื•ืช ื‘ืจื™ืจืช ื”ืžื—ื“ืœ ืื™ื ืŸ ืžื›ื•ื‘ื“ื•ืช ื‘ืคืจื•ืคื™ืœื™ WSL ืขื ื›ื™ื ื•ื™ื™ื ื•ืžืฉืชื ื™ ืกื‘ื™ื‘ื”.
  • ื”ืฉืœืžืช ื ืชื™ื‘ ืœื™ื ื•ืงืก ืื™ื ื” ื ืชืžื›ืช.
  • ื”ืฉืœืžืช ืคืงื•ื“ื” ืื™ื ื” ื ืชืžื›ืช.
  • ื”ืฉืœืžืช ื˜ื™ืขื•ื ื™ื ืื™ื ื” ื ืชืžื›ืช.

ื›ืชื•ืฆืื” ืžื›ืš, ืคืงื•ื“ื•ืช ืœื™ื ื•ืงืก ืžื˜ื•ืคืœื•ืช ื›ืžื• ืื–ืจื—ื™ื ืกื•ื’ ื‘' ืชื—ืช Windows - ื•ื”ืŸ ืงืฉื•ืช ื™ื•ืชืจ ืœืฉื™ืžื•ืฉ ืžืืฉืจ ืคืงื•ื“ื•ืช ืžืงื•ืจื™ื•ืช. ื›ื“ื™ ืœื”ืฉื•ื•ืช ืืช ื–ื›ื•ื™ื•ืชื™ื”ื, ื™ืฉ ืฆื•ืจืš ืœืคืชื•ืจ ืืช ื”ื‘ืขื™ื•ืช ื”ืžืคื•ืจื˜ื•ืช.

ืขื˜ื™ืคื•ืช ืคื•ื ืงืฆื™ื•ืช ืฉืœ PowerShell

ืขื ืขื˜ื™ืคื•ืช ืคื•ื ืงืฆื™ื•ืช ืฉืœ PowerShell, ืื ื• ื™ื›ื•ืœื™ื ืœื”ื•ืกื™ืฃ ื”ืฉืœืžืช ืคืงื•ื“ื•ืช ื•ืœื‘ื˜ืœ ืืช ื”ืฆื•ืจืš ื‘ืงื™ื“ื•ืžื•ืช wsl, ืชืจื’ื•ื ื ืชื™ื‘ื™ Windows ืœื ืชื™ื‘ื™ WSL. ื“ืจื™ืฉื•ืช ื‘ืกื™ืกื™ื•ืช ืœืงื•ื ื›ื™ื•ืช:

  • ืขื‘ื•ืจ ื›ืœ ืคืงื•ื“ืช ืœื™ื ื•ืงืก ื—ื™ื™ื‘ืช ืœื”ื™ื•ืช ืžืขื˜ืคืช ืคื•ื ืงืฆื™ื” ืื—ืช ืขื ืื•ืชื• ืฉื.
  • ื”ืžืขื˜ืคืช ื—ื™ื™ื‘ืช ืœื–ื”ื•ืช ืืช ื ืชื™ื‘ื™ Windows ืฉื”ื•ืขื‘ืจื• ื›ืืจื’ื•ืžื ื˜ื™ื ื•ืœื”ืžื™ืจ ืื•ืชื ืœื ืชื™ื‘ื™ WSL.
  • ื”ืงืœื™ืคื” ืฆืจื™ื›ื” ืœื”ืชืงืฉืจ wsl ืขื ืคืงื•ื“ืช Linux ื”ืžืชืื™ืžื” ืœื›ืœ ืงืœื˜ ืฆื™ื ื•ืจ ื•ื”ืขื‘ืจืช ื›ืœ ืืจื’ื•ืžื ื˜ื™ื ืฉืœ ืฉื•ืจืช ื”ืคืงื•ื“ื” ื”ืžื•ืขื‘ืจื™ื ืœืคื•ื ืงืฆื™ื”.

ืžื›ื™ื•ื•ืŸ ืฉื ื™ืชืŸ ืœื”ื—ื™ืœ ืืช ื”ืชื‘ื ื™ืช ื”ื–ื• ืขืœ ื›ืœ ืคืงื•ื“ื”, ืื ื• ื™ื›ื•ืœื™ื ืœืคืฉื˜ ืืช ื”ื”ื’ื“ืจื” ืฉืœ ืขื˜ื™ืคื•ืช ืืœื• ื•ืœื™ืฆื•ืจ ืื•ืชืŸ ื‘ืื•ืคืŸ ื“ื™ื ืžื™ ืžืชื•ืš ืจืฉื™ืžื” ืฉืœ ืคืงื•ื“ื•ืช ืœื™ื™ื‘ื•ื.

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

ืจืฉื™ืžื” $command ืžื’ื“ื™ืจ ืคืงื•ื“ื•ืช ื™ื™ื‘ื•ื. ืœืื—ืจ ืžื›ืŸ ืื ื• ื™ื•ืฆืจื™ื ื‘ืื•ืคืŸ ื“ื™ื ืžื™ ืžืขื˜ืคืช ืคื•ื ืงืฆื™ื•ืช ืขื‘ื•ืจ ื›ืœ ืื—ื“ ืžื”ื ื‘ืืžืฆืขื•ืช ื”ืคืงื•ื“ื” Invoke-Expression (ืขืœ ื™ื“ื™ ื”ืกืจืช ืชื—ื™ืœื” ื›ื™ื ื•ื™ื™ื ืฉื™ืชื ื’ืฉื• ืขื ื”ืคื•ื ืงืฆื™ื”).

ื”ืคื•ื ืงืฆื™ื” ื—ื•ื–ืจืช ืขืœ ืืจื’ื•ืžื ื˜ื™ื ืฉืœ ืฉื•ืจืช ื”ืคืงื•ื“ื”, ืงื•ื‘ืขืช ื ืชื™ื‘ื™ื ืฉืœ Windows ื‘ืืžืฆืขื•ืช ืคืงื•ื“ื•ืช Split-Path ะธ Test-Pathื•ืœืื—ืจ ืžื›ืŸ ืžืžื™ืจ ื ืชื™ื‘ื™ื ืืœื” ืœื ืชื™ื‘ื™ WSL. ืื ื• ืžืคืขื™ืœื™ื ืืช ื”ืฉื‘ื™ืœื™ื ื“ืจืš ืคื•ื ืงืฆื™ื™ืช ืขื•ื–ืจ Format-WslArgument, ืื•ืชื• ื ื’ื“ื™ืจ ื‘ื”ืžืฉืš. ื”ื•ื ื‘ื•ืจื— ืžืชื•ื•ื™ื ืžื™ื•ื—ื“ื™ื ื›ืžื• ืจื•ื•ื—ื™ื ื•ืกื•ื’ืจื™ื™ื ืฉืื—ืจืช ื”ื™ื• ืžืชืคืจืฉื™ื ื‘ืฆื•ืจื” ืœื ื ื›ื•ื ื”.

ืœื‘ืกื•ืฃ, ืื ื• ืžืขื‘ื™ืจื™ื wsl ืงืœื˜ ืฆื™ื ื•ืจ ื•ื›ืœ ืืจื’ื•ืžื ื˜ื™ื ืฉืœ ืฉื•ืจืช ื”ืคืงื•ื“ื”.

ืขื ื”ืขื˜ื™ืคื•ืช ื”ืืœื” ืืชื” ื™ื›ื•ืœ ืœืงืจื•ื ืœืคืงื•ื“ื•ืช ืœื™ื ื•ืงืก ื”ืžื•ืขื“ืคื•ืช ืขืœื™ืš ื‘ืฆื•ืจื” ื˜ื‘ืขื™ืช ื™ื•ืชืจ ืžื‘ืœื™ ืœื”ื•ืกื™ืฃ ืงื™ื“ื•ืžืช wsl ื•ื‘ืœื™ ืœื“ืื•ื’ ืœื’ื‘ื™ ืื•ืคืŸ ื”ื”ืžืจื” ืฉืœ ื”ืฉื‘ื™ืœื™ื:

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

ืงื‘ื•ืฆืช ื”ืคืงื•ื“ื•ืช ื”ื‘ืกื™ืกื™ืช ืžื•ืฆื’ืช ื›ืืŸ, ืื‘ืœ ืืชื” ื™ื›ื•ืœ ืœื™ืฆื•ืจ ืžืขื˜ืคืช ืขื‘ื•ืจ ื›ืœ ืคืงื•ื“ืช ืœื™ื ื•ืงืก ืขืœ ื™ื“ื™ ื”ื•ืกืคืชื” ืœืจืฉื™ืžื”. ืื ืชื•ืกื™ืฃ ืืช ื”ืงื•ื“ ื”ื–ื” ืœืฉืœืš ืคืจื•ืคื™ืœ PowerShell, ื”ืคืงื•ื“ื•ืช ื”ืœืœื• ื™ื”ื™ื• ื–ืžื™ื ื•ืช ืœืš ื‘ื›ืœ ื”ืคืขืœืช PowerShell, ื‘ื“ื™ื•ืง ื›ืžื• ืคืงื•ื“ื•ืช ืžืงื•ืจื™ื•ืช!

ื”ื’ื“ืจื•ืช ื‘ืจื™ืจืช ืžื—ื“ืœ

ื‘ืœื™ื ื•ืงืก, ืžืงื•ื‘ืœ ืœื”ื’ื“ื™ืจ ื›ื™ื ื•ื™ื™ื ื•/ืื• ืžืฉืชื ื™ ืกื‘ื™ื‘ื” ื‘ืคืจื•ืคื™ืœื™ ื”ืชื—ื‘ืจื•ืช, ื”ื’ื“ืจืช ืคืจืžื˜ืจื™ ื‘ืจื™ืจืช ืžื—ื“ืœ ืขื‘ื•ืจ ืคืงื•ื“ื•ืช ื‘ืฉื™ืžื•ืฉ ืชื›ื•ืฃ (ืœื“ื•ื’ืžื”, alias ls=ls -AFh ืื• export LESS=-i). ืื—ื“ ื”ื—ืกืจื•ื ื•ืช ืฉืœ ืคืจื•ืงืกื™ ื“ืจืš ืžืขื˜ืคืช ืœื ืื™ื ื˜ืจืืงื˜ื™ื‘ื™ืช wsl.exe - ืฉื”ืคืจื•ืคื™ืœื™ื ืื™ื ื ื ื˜ืขื ื™ื, ื•ืœื›ืŸ ืืคืฉืจื•ื™ื•ืช ืืœื• ืื™ื ืŸ ื–ืžื™ื ื•ืช ื›ื‘ืจื™ืจืช ืžื—ื“ืœ (ื›ืœื•ืžืจ. ls ื‘-WSL ื• wsl ls ื™ืชื ื”ื’ ืื—ืจืช ืขื ื”ื›ื™ื ื•ื™ ืฉื”ื•ื’ื“ืจ ืœืขื™ืœ).

PowerShell ืžืกืคืงืช $PSDefaultParameterValues, ืžื ื’ื ื•ืŸ ืกื˜ื ื“ืจื˜ื™ ืœื”ื’ื“ืจืช ืคืจืžื˜ืจื™ ื‘ืจื™ืจืช ืžื—ื“ืœ, ืืš ืจืง ืขื‘ื•ืจ cmdlets ื•ืคื•ื ืงืฆื™ื•ืช ืžืชืงื“ืžื•ืช. ื›ืžื•ื‘ืŸ, ืื ื—ื ื• ื™ื›ื•ืœื™ื ืœื™ืฆื•ืจ ืคื•ื ืงืฆื™ื•ืช ืžืชืงื“ืžื•ืช ืžื”ืงืœื™ืคื•ืช ืฉืœื ื•, ืื‘ืœ ื–ื” ืžืฆื™ื’ ืกื™ื‘ื•ื›ื™ื ืžื™ื•ืชืจื™ื (ืœื“ื•ื’ืžื”, PowerShell ืžืชืื ืฉืžื•ืช ืคืจืžื˜ืจื™ื ื—ืœืงื™ื™ื (ืœื“ื•ื’ืžื”, -a ืžืชืื ืขื -ArgumentList), ืฉืชืชื ื’ืฉ ืขื ืคืงื•ื“ื•ืช ืœื™ื ื•ืงืก ืฉืœื•ืงื—ื•ืช ืฉืžื•ืช ื—ืœืงื™ื™ื ื›ืืจื’ื•ืžื ื˜ื™ื), ื•ื”ืชื—ื‘ื™ืจ ืœื”ื’ื“ืจืช ืขืจื›ื™ ื‘ืจื™ืจืช ืžื—ื“ืœ ืœื ื™ื”ื™ื” ื”ืžืชืื™ื ื‘ื™ื•ืชืจ (ืืจื’ื•ืžื ื˜ื™ื ื‘ืจื™ืจืช ืžื—ื“ืœ ื“ื•ืจืฉื™ื ืืช ืฉื ื”ืคืจืžื˜ืจ ื‘ืžืคืชื—, ืœื ืจืง ืืช ืฉื ื”ืคืงื•ื“ื”) .

ืขื ื–ืืช, ืขื ืฉื™ื ื•ื™ ืงืœ ื‘ืงื•ื ื›ื™ื•ืช ืฉืœื ื•, ื ื•ื›ืœ ืœื™ื™ืฉื ืžื•ื“ืœ ื“ื•ืžื” ืœื–ื” $PSDefaultParameterValues, ื•ืืคืฉืจ ืืคืฉืจื•ื™ื•ืช ื‘ืจื™ืจืช ืžื—ื“ืœ ืขื‘ื•ืจ ืคืงื•ื“ื•ืช ืœื™ื ื•ืงืก!

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

ื—ื•ึนืœึตืฃ $WslDefaultParameterValues ืœืฉื•ืจืช ื”ืคืงื•ื“ื”, ืื ื• ืฉื•ืœื—ื™ื ืคืจืžื˜ืจื™ื ื‘ืืžืฆืขื•ืช wsl.exe. ืœื”ืœืŸ ื ืจืื” ื›ื™ืฆื“ ืœื”ื•ืกื™ืฃ ื”ื•ืจืื•ืช ืœืคืจื•ืคื™ืœ PowerShell ืฉืœืš ื›ื“ื™ ืœื”ื’ื“ื™ืจ ืืช ื”ื’ื“ืจื•ืช ื‘ืจื™ืจืช ื”ืžื—ื“ืœ. ืขื›ืฉื™ื• ืื ื—ื ื• ื™ื›ื•ืœื™ื ืœืขืฉื•ืช ืืช ื–ื”!

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

ืžื›ื™ื•ื•ืŸ ืฉื”ืคืจืžื˜ืจื™ื ืžืขื•ืฆื‘ื™ื ืœืื—ืจ $PSDefaultParameterValuesืืชื” ื™ื›ื•ืœ ืงืœ ืœื”ืฉื‘ื™ืช ืื•ืชื ื‘ืื•ืคืŸ ื–ืžื ื™ ืขืœ ื™ื“ื™ ื”ืชืงื ืช ื”ืžืคืชื— "Disabled" ืœืชื•ืš ืžืฉืžืขื•ืช $true. ื™ืชืจื•ืŸ ื ื•ืกืฃ ืฉืœ ื˜ื‘ืœืช hash ื ืคืจื“ืช ื”ื•ื ื”ื™ื›ื•ืœืช ืœื”ืฉื‘ื™ืช $WslDefaultParameterValues ื‘ื ืคืจื“ ืž $PSDefaultParameterValues.

ื”ืฉืœืžืช ื˜ื™ืขื•ืŸ

PowerShell ืžืืคืฉืจ ืœืš ืœืจืฉื•ื ื˜ืจื™ื™ืœืจื™ื ืฉืœ ืืจื’ื•ืžื ื˜ื™ื ื‘ืืžืฆืขื•ืช ื”ืคืงื•ื“ื” Register-ArgumentCompleter. ืœื‘ืฉ ื™ืฉ ืขื•ืฆืžื” ื›ืœื™ ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช ื”ื ื™ืชื ื™ื ืœืชื›ื ื•ืช. WSL ืžืืคืฉืจ ืœืš ืœื”ืชืงืฉืจ ืœ-bash ืž- PowerShell. ืื ื ื•ื›ืœ ืœืจืฉื•ื ื”ืฉืœืžื•ืช ืืจื’ื•ืžื ื˜ื™ื ืขื‘ื•ืจ ืขื•ื˜ืคื™ ืคื•ื ืงืฆื™ื•ืช PowerShell ืฉืœื ื• ื•ืœืงืจื•ื bash ื›ื“ื™ ืœื™ืฆื•ืจ ืืช ื”ื”ืฉืœืžื•ืช, ื ืงื‘ืœ ื”ืฉืœืžืช ืืจื’ื•ืžื ื˜ื™ื ืžืœืื” ื‘ืื•ืชื” ื“ื™ื•ืง ื›ืžื• 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]
    }
}

ื”ืงื•ื“ ืžืขื˜ ืฆืคื•ืฃ ืžื‘ืœื™ ืœื”ื‘ื™ืŸ ื—ืœืง ืžื”ืคื•ื ืงืฆื™ื•ืช ื”ืคื ื™ืžื™ื•ืช ืฉืœ bash, ืื‘ืœ ื‘ืขืฆื ืžื” ืฉืื ื—ื ื• ืขื•ืฉื™ื ื–ื”:

  • ืจื™ืฉื•ื ืžืฉืœื™ื ืืจื’ื•ืžื ื˜ื™ื ืขื‘ื•ืจ ื›ืœ ืขื˜ื™ืคื•ืช ื”ืคื•ื ืงืฆื™ื•ืช ืฉืœื ื• ืขืœ ื™ื“ื™ ื”ืขื‘ืจืช ืจืฉื™ืžื” $commands ื‘ืคืจืžื˜ืจ -CommandName ืขื‘ื•ืจ Register-ArgumentCompleter.
  • ืื ื• ืžืžืคื™ื ื›ืœ ืคืงื•ื“ื” ืœืคื•ื ืงืฆื™ื™ืช ื”ืžืขื˜ืคืช ืฉื‘ื” ืžืฉืชืžืฉืช bash ืœื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช (ื›ื“ื™ ืœื”ื’ื“ื™ืจ ืžืคืจื˜ื™ ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช, bash ืžืฉืชืžืฉืช $F, ืงื™ืฆื•ืจ ืฉืœ complete -F <FUNCTION>).
  • ื”ืžืจืช ืืจื’ื•ืžื ื˜ื™ื ืฉืœ PowerShell $wordToComplete, $commandAst ะธ $cursorPosition ืœืคื•ืจืžื˜ ื”ืžืฆื•ืคื” ืžืคื•ื ืงืฆื™ื•ืช ื”ื”ืฉืœืžื” ื”ืื•ื˜ื•ืžื˜ื™ืช ืฉืœ bash ื‘ื”ืชืื ืœืžืคืจื˜ื™ื ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช ื”ื ื™ืชื ืช ืœืชื›ื ื•ืช ืœึทื—ึฒื‘ื•ึนื˜.
  • ืื ื• ืžืจื›ื™ื‘ื™ื ืฉื•ืจืช ืคืงื•ื“ื” ืœื”ืขื‘ืจื” wsl.exe, ื”ืžื‘ื˜ื™ื— ืฉื”ืกื‘ื™ื‘ื” ืžื•ื’ื“ืจืช ื›ื”ืœื›ื”, ืงื•ืจื ืœืคื•ื ืงืฆื™ื™ืช ื”ื”ืฉืœืžื” ื”ืื•ื˜ื•ืžื˜ื™ืช ื”ืžืชืื™ืžื”, ื•ืžื•ืฆื™ื ืืช ื”ืชื•ืฆืื•ืช ื‘ืฉื•ืจื” ืื—ืจ ืฉื•ืจื”.
  • ื•ืื– ืื ื—ื ื• ืžืชืงืฉืจื™ื wsl ืขื ืฉื•ืจืช ื”ืคืงื•ื“ื”, ืื ื• ืžืคืจื™ื“ื™ื ืืช ื”ืคืœื˜ ืœืคื™ ืžืคืจื™ื“ื™ ืฉื•ืจื•ืช ื•ืžื™ื™ืฆืจื™ื ืขื‘ื•ืจ ื›ืœ ืื—ื“ ืžื”ื CompletionResults, ืžื™ื•ืŸ ืฉืœื”ื ื•ื”ื™ืžืœื˜ื•ืช ืชื•ื•ื™ื ื›ื’ื•ืŸ ืจื•ื•ื—ื™ื ื•ืกื•ื’ืจื™ื™ื ืฉืื—ืจืช ื”ื™ื• ืžืชืคืจืฉื™ื ืœื ื ื›ื•ืŸ.

ื›ืชื•ืฆืื” ืžื›ืš, ืžืขื˜ืคื•ืช ื”ืคืงื•ื“ื•ืช ืฉืœ ืœื™ื ื•ืงืก ืฉืœื ื• ื™ืฉืชืžืฉื• ื‘ื“ื™ื•ืง ื‘ืื•ืชื” ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช ื›ืžื• bash! ืœื“ื•ื’ืžื”:

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

ื›ืœ ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช ืžืกืคืงืช ืขืจื›ื™ื ืกืคืฆื™ืคื™ื™ื ืœืืจื’ื•ืžื ื˜ ื”ืงื•ื“ื, ื•ืงื•ืจืืช ื ืชื•ื ื™ ืชืฆื•ืจื” ื›ื’ื•ืŸ ืžืืจื—ื™ื ื™ื“ื•ืขื™ื ืž-WSL!

<TAB> ื™ืขื‘ื•ืจ ืขืœ ื”ืคืจืžื˜ืจื™ื. <Ctrl + ะฟั€ะพะฑะตะป> ื™ืฆื™ื’ ืืช ื›ืœ ื”ืืคืฉืจื•ื™ื•ืช ื”ื–ืžื™ื ื•ืช.

ื‘ื ื•ืกืฃ, ืžื›ื™ื•ื•ืŸ ืฉื™ืฉ ืœื ื• ื›ืขืช ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช ืฉืœ bash, ืืชื” ื™ื›ื•ืœ ืœื”ืฉืœื™ื ืื•ื˜ื•ืžื˜ื™ืช ื ืชื™ื‘ื™ ืœื™ื ื•ืงืก ื™ืฉื™ืจื•ืช ื‘-PowerShell!

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

ื‘ืžืงืจื™ื ื‘ื”ื ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช ืฉืœ bash ืื™ื ื” ืžื ื™ื‘ื” ืชื•ืฆืื•ืช, PowerShell ื—ื•ื–ืจ ืœื ืชื™ื‘ื™ ื‘ืจื™ืจืช ื”ืžื—ื“ืœ ืฉืœ Windows. ื›ืš, ื‘ืคื•ืขืœ, ืืชื” ื™ื›ื•ืœ ืœื”ืฉืชืžืฉ ื‘ืฉื ื™ ื”ื ืชื™ื‘ื™ื ื‘ื• ื–ืžื ื™ืช ืœืคื™ ืฉื™ืงื•ืœ ื“ืขืชืš.

ืžืกืงื ื”

ื‘ืืžืฆืขื•ืช PowerShell ื•-WSL, ืื ื• ื™ื›ื•ืœื™ื ืœืฉืœื‘ ืคืงื•ื“ื•ืช ืœื™ื ื•ืงืก ื‘-Windows ื›ื™ื™ืฉื•ืžื™ื ืžืงื•ืจื™ื™ื. ืื™ืŸ ืฆื•ืจืš ืœื—ืคืฉ ื‘ื ื™ื™ืช Win32 ืื• ื›ืœื™ ืขื–ืจ ืฉืœ ืœื™ื ื•ืงืก ืื• ืœื”ืคืจื™ืข ืœื–ืจื™ืžืช ื”ืขื‘ื•ื“ื” ืฉืœืš ืขืœ ื™ื“ื™ ืžืขื‘ืจ ืœืžืขื˜ืคืช ืœื™ื ื•ืงืก. ืจึทืง ืœื”ืชืงื™ืŸ WSL, ืœื”ื’ื“ื™ืจ ืคืจื•ืคื™ืœ PowerShell ะธ ืจืฉื•ื ืืช ื”ืคืงื•ื“ื•ืช ืฉื‘ืจืฆื•ื ืš ืœื™ื™ื‘ื! ื”ืฉืœืžื” ืื•ื˜ื•ืžื˜ื™ืช ืขืฉื™ืจื” ืขื‘ื•ืจ ืคืจืžื˜ืจื™ ืคืงื•ื“ื•ืช ื•ื ืชื™ื‘ื™ ืงื‘ืฆื™ื ืฉืœ Linux ื•-Windows ื”ื™ื ืคื•ื ืงืฆื™ื•ื ืœื™ื•ืช ืฉืื™ื ื” ื–ืžื™ื ื” ืืคื™ืœื• ื‘ืคืงื•ื“ื•ืช ืžืงื•ืจื™ื•ืช ืฉืœ Windows ื›ื™ื•ื.

ืงื•ื“ ื”ืžืงื•ืจ ื”ืžืœื ื”ืžืชื•ืืจ ืœืขื™ืœ, ื›ืžื• ื’ื ื”ื ื—ื™ื•ืช ื ื•ืกืคื•ืช ืœืฉื™ืœื•ื‘ื• ื‘ื–ืจื™ืžืช ื”ืขื‘ื•ื“ื” ืฉืœืš, ื–ืžื™ืŸ ื›ืืŸ.

ืื™ืœื• ืคืงื•ื“ื•ืช Linux ื”ื›ื™ ืฉื™ืžื•ืฉื™ื•ืช ื‘ืขื™ื ื™ืš? ืื™ืœื• ื“ื‘ืจื™ื ื ืคื•ืฆื™ื ื ื•ืกืคื™ื ื—ืกืจื™ื ื‘ืขื‘ื•ื“ื” ื‘-Windows? ื›ืชื‘ื• ื‘ืชื’ื•ื‘ื•ืช ืื• ื‘-GitHub!

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”