Интегратсияи фармонҳои Linux ба Windows бо истифода аз PowerShell ва WSL

Саволи маъмулии таҳиягарони Windows: "Чаро то ҳол вуҷуд надорад <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>?. Новобаста аз он ки он як лағжиши пурқувват аст less ё асбобҳои шинос grep ё sed, Таҳиягарони Windows мехоҳанд, ки дар кори ҳаррӯзаи худ ба ин фармонҳо дастрасии осон дошта бошанд.

Зерсистемаи Windows барои Linux (WSL) дар ин бобат кадами калон ба пеш гузошт. Он ба шумо имкон медиҳад, ки фармонҳои Linuxро аз Windows тавассути прокси-синг кардани онҳо занг занед wsl.exe (масалан, wsl ls). Гарчанде ки ин беҳбудии назаррас аст, ин вариант аз як қатор камбудиҳо дучор мешавад.

  • Иловаи ҳамаҷониба wsl дилгиркунанда ва ғайритабиӣ.
  • Роҳҳои Windows дар аргументҳо на ҳама вақт кор мекунанд, зеро хатҳои баръакс ҳамчун аломатҳои фирорӣ тафсир карда мешаванд, на ҷудокунандаи директория.
  • Роҳҳои Windows дар аргументҳо ба нуқтаи мувофиқи васлкунӣ дар WSL тарҷума карда намешаванд.
  • Танзимоти пешфарз дар профилҳои WSL бо тахаллусҳо ва тағирёбандаҳои муҳити зист риоя намешаванд.
  • Анҷоми роҳи Linux дастгирӣ намешавад.
  • Иҷрои фармон дастгирӣ намешавад.
  • Анҷом додани аргумент дастгирӣ намешавад.

Дар натиҷа, ба фармонҳои Linux ҳамчун шаҳрвандони дараҷаи дуюм дар Windows муносибат мекунанд ва истифодаашон нисбат ба фармонҳои маҳаллӣ мушкилтар аст. Барои баробар кардани хукуки онхо проблемахои номбаршударо хал кардан лозим аст.

Сарпӯши функсияҳои PowerShell

Бо печонидани функсияҳои PowerShell, мо метавонем ба итмом расонидани фармон илова кунем ва ниёз ба префиксҳоро бартараф кунем wsl, тарҷумаи роҳҳои Windows ба роҳҳои WSL. Талаботи асосӣ барои чӯб:

  • Барои ҳар як фармони Linux бояд як бастаи функсия бо ҳамон ном мавҷуд бошад.
  • Қабат бояд роҳҳои 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 вуруди қубур ва ҳама гуна далелҳои сатри фармон.

Бо ин парпечҳо шумо метавонед фармонҳои дӯстдоштаи Linux-и худро ба таври табиӣ бидуни илова префикс даъват кунед wsl ва бе ташвиш дар бораи чӣ гуна табдил додани роҳҳо:

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

Маҷмӯи асосии фармонҳо дар ин ҷо нишон дода шудааст, аммо шумо метавонед барои ҳама фармонҳои Linux ҷилди онро бо илова кардани он ба рӯйхат эҷод кунед. Агар шумо ин кодро ба шумо илова кунед профил PowerShell, ин фармонҳо ба шумо дар ҳар як сессияи PowerShell дастрас хоҳанд буд, мисли фармонҳои маҳаллӣ!

Танзимоти пешфарз

Дар Linux, муқаррар кардани тахаллусҳо ва/ё тағирёбандаҳои муҳити зист дар профилҳои воридшавӣ, муқаррар кардани параметрҳои пешфарз барои фармонҳои зуд-зуд истифодашаванда маъмул аст (масалан, alias ls=ls -AFh ё export LESS=-i). Яке аз нуқсонҳои прокси тавассути қабати ғайри интерактивӣ wsl.exe - ки профилҳо бор карда нашудаанд, бинобар ин, ин интихобҳо ба таври нобаёнӣ дастрас нестанд (яъне. ls дар WSL ва wsl ls бо тахаллуси дар боло муайяншуда дигар хел рафтор хоҳад кард).

PowerShell таъмин менамояд $PSDefaultParameterValues, механизми стандартӣ барои муайян кардани параметрҳои пешфарз, аммо танҳо барои cmdlets ва функсияҳои пешрафта. Албатта, мо метавонем аз снарядҳои худ вазифаҳои пешрафта созем, аммо ин мушкилиҳои нолозимро ба вуҷуд меорад (масалан, PowerShell номҳои қисман параметрҳоро мувофиқат мекунад (масалан, -a бо ҳам алоқаманд аст -ArgumentList), ки бо фармонҳои Linux, ки номҳои қисман ҳамчун аргумент мегиранд) мухолифат мекунанд ва синтаксис барои муайян кардани арзишҳои пешфарз мувофиқтарин нахоҳад буд (аргументҳои пешфарз номи параметрро дар калид талаб мекунанд, на танҳо номи фармон) .

Бо вуҷуди ин, бо тағир додани каме ба снарядҳои мо, мо метавонем модели шабеҳро татбиқ кунем $PSDefaultParameterValues, ва имконоти пешфарзро барои фармонҳои 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 ' ')
    }
}

Гузариш $WslDefaultParameterValues ба сатри фармон, мо параметрҳоро тавассути wsl.exe. Дар зер нишон дода шудааст, ки чӣ тавр илова кардани дастурҳо ба профили PowerShell-и худ барои танзими танзимоти пешфарз. Акнун мо метавонем ин корро кунем!

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

Азбаски параметрҳо пас аз моделсозӣ карда мешаванд $PSDefaultParameterValues, Ту метавонӣ хомӯш кардани онҳо осон аст муваққатан тавассути насб кардани калид "Disabled" ба маъно $true. Бартарии иловагии ҷадвали шудаи алоҳида ин қобилияти хомӯш кардан аст $WslDefaultParameterValues ҷудо аз $PSDefaultParameterValues.

Анҷоми баҳс

PowerShell ба шумо имкон медиҳад, ки трейлерҳои аргументро бо истифода аз фармон сабт кунед Register-ArgumentCompleter. Bash дорои қудрат аст асбобҳои автоматии барномарезишаванда. WSL ба шумо имкон медиҳад, ки аз PowerShell bash занг занед. Агар мо метавонем ба итмомрасии аргументҳо барои парпечҳои функсияи 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, ҷудо кардани онҳо ва фирор кардани аломатҳо ба монанди фосила ва қавс, ки дар акси ҳол нодуруст шарҳ дода мешаванд.

Дар натиҷа, қабатҳои фармони Linux-и мо маҳз ҳамон худкоркуниро ҳамчун bash истифода хоҳанд бурд! Барои намуна:

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

Ҳар як пуркунии худкор арзишҳоеро, ки ба далели қаблӣ хос аст, таъмин мекунад ва маълумоти конфигуратсияро мехонад, ба монанди ҳостҳои маълум аз WSL!

<TAB> дар байни параметрҳо давр мезананд. <Ctrl + пробел> ҳамаи имконоти мавҷударо нишон медиҳад.

Ғайр аз он, азбаски мо ҳоло худкорпуркунии bash дорем, шумо метавонед роҳҳои Linux-ро мустақиман дар PowerShell худкор пур кунед!

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

Дар ҳолатҳое, ки автоматии bash ягон натиҷа намедиҳад, PowerShell ба роҳҳои пешфарзии Windows бармегардад. Ҳамин тариқ, дар амал шумо метавонед ҳамзамон ҳарду роҳро бо ихтиёри худ истифода баред.

хулоса

Бо истифода аз PowerShell ва WSL, мо метавонем фармонҳои Linux-ро ба Windows ҳамчун замимаҳои маҳаллӣ ворид кунем. Ҷустуҷӯи сохтани Win32 ё утилитаҳои Linux ё халалдор кардани ҷараёни кори шумо тавассути рафтан ба қабати Linux лозим нест. Танҳо WSL насб кунед, танзим кунед Профили PowerShell и фармонҳоеро номбар кунед, ки шумо мехоҳед ворид кунед! Параметрҳои фармонҳои Linux ва Windows ва роҳҳои файл ин функсияест, ки ҳатто дар фармонҳои аслии Windows имрӯз мавҷуд нест.

Рамзи пурраи сарчашмаи дар боло тавсифшуда ва инчунин дастурҳои иловагӣ барои ворид кардани он ба ҷараёни кори шумо дастрас аст дар ин ҷо.

Кадом фармонҳои Linux ба шумо муфидтар аст? Ҳангоми кор дар Windows боз кадом чизҳои маъмулӣ намерасанд? Дар шарҳҳо нависед ё дар GitHub!

Манбаъ: will.com

Илова Эзоҳ