PowerShell සහ WSL භාවිතයෙන් Linux විධාන වින්ඩෝස් වෙත ඒකාබද්ධ කිරීම

වින්ඩෝස් සංවර්ධකයින්ගෙන් සාමාන්‍ය ප්‍රශ්නයක්: “ඇයි තවමත් නැත්තේ <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>?. එය බලවත් ස්වයිප් එකක්ද යන්න less හෝ හුරුපුරුදු මෙවලම් grep හෝ sed, වින්ඩෝස් සංවර්ධකයින්ට ඔවුන්ගේ දෛනික වැඩ වලදී මෙම විධාන වලට පහසුවෙන් ප්‍රවේශ වීමට අවශ්‍ය වේ.

ලිනක්ස් සඳහා වින්ඩෝස් උප පද්ධතිය (WSL) මේ සම්බන්ධයෙන් විශාල ඉදිරි පියවරක් තබා ඇත. වින්ඩෝස් වෙතින් ලිනක්ස් විධානයන් ප්‍රොක්සි කිරීම මගින් ඇමතීමට එය ඔබට ඉඩ සලසයි wsl.exe (උදා. wsl ls) මෙය සැලකිය යුතු දියුණුවක් වුවද, මෙම විකල්පය අවාසි ගණනාවකින් පීඩා විඳිති.

  • සර්වසම්පූර්ණ එකතු කිරීම wsl වෙහෙසකර සහ අස්වාභාවික.
  • ඩිරෙක්ටරි බෙදුම්කරුවන්ට වඩා backslashes ගැලවීමේ අක්ෂර ලෙස අර්ථකථනය කරන නිසා තර්ක වල Windows paths සැමවිටම ක්‍රියා නොකරයි.
  • තර්ක වල වින්ඩෝස් මාර්ග WSL හි අනුරූප සවි කිරීමේ ලක්ෂ්‍යයට පරිවර්තනය නොවේ.
  • අන්වර්ථ සහ පරිසර විචල්‍ය සහිත WSL පැතිකඩවල පෙරනිමි සැකසුම් වලට ගරු නොකෙරේ.
  • Linux මාර්ගය සම්පූර්ණ කිරීම සඳහා සහය නොදක්වයි.
  • විධානය සම්පූර්ණ කිරීම සඳහා සහය නොදක්වයි.
  • තර්කය සම්පූර්ණ කිරීම සඳහා සහය නොදක්වයි.

එහි ප්‍රතිඵලයක් වශයෙන්, Linux විධාන Windows යටතේ දෙවන පන්තියේ පුරවැසියන් ලෙස සලකනු ලබන අතර දේශීය විධාන වලට වඩා භාවිතා කිරීමට අපහසු වේ. ඔවුන්ගේ අයිතිවාසිකම් සමාන කිරීම සඳහා, ලැයිස්තුගත ගැටළු විසඳීම අවශ්ය වේ.

PowerShell ක්‍රියාකාරී දවටන

PowerShell ක්‍රියාකාරී දවටන සමඟ, අපට විධාන සම්පූර්ණ කිරීම එක් කළ හැකි අතර උපසර්ග අවශ්‍යතාවය ඉවත් කළ හැකිය. wsl, වින්ඩෝස් මාර්ග WSL මාර්ග බවට පරිවර්තනය කිරීම. ෂෙල් වෙඩි සඳහා මූලික අවශ්යතා:

  • සෑම ලිනක්ස් විධානයක් සඳහාම එකම නම සහිත එක් ක්‍රියාකාරී දවටනයක් තිබිය යුතුය.
  • කවචය විසින් සම්මත කරන ලද වින්ඩෝස් මාර්ග තර්ක ලෙස හඳුනාගෙන ඒවා WSL මාර්ග බවට පරිවර්තනය කළ යුතුය.
  • කවචය ඇමතිය යුතුය wsl ඕනෑම නල මාර්ග ආදානයකට සුදුසු Linux විධානය සමඟින් සහ ශ්‍රිතයට යවන ඕනෑම විධාන රේඛා තර්කයක් ලබා දීම.

මෙම රටාව ඕනෑම විධානයකට යෙදිය හැකි බැවින්, අපට මෙම wrappers හි නිර්වචනය වියුක්ත කර ආනයනය කිරීමට විධාන ලැයිස්තුවකින් ගතිකව ඒවා ජනනය කළ හැක.

# 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 (ප්‍රථමයෙන් ශ්‍රිතයට පටහැනි අන්වර්ථ නාමයන් ඉවත් කිරීමෙන්).

ශ්‍රිතය විධාන රේඛා තර්ක හරහා පුනරාවර්තනය වේ, විධාන භාවිතයෙන් වින්ඩෝස් මාර්ග තීරණය කරයි 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 විධානයක් සඳහා shell එකක් සෑදිය හැක. ඔබ මෙම කේතය ඔබේ එකට එකතු කළහොත් පැතිකඩ PowerShell, මෙම විධාන ස්වදේශීය විධාන මෙන් සෑම PowerShell සැසියකදීම ඔබට ලබා ගත හැක!

පෙරනිමි සැකසුම්

Linux හි, පිවිසුම් පැතිකඩවල අන්වර්ථ සහ/හෝ පරිසර විචල්‍ය නිර්වචනය කිරීම සාමාන්‍ය දෙයකි, නිතර භාවිතා කරන විධාන සඳහා පෙරනිමි පරාමිති සැකසීම (උදාහරණයක් ලෙස, alias ls=ls -AFh හෝ export LESS=-i) අන්තර්ක්‍රියාකාරී නොවන කවචයක් හරහා ප්‍රොක්සි කිරීමේ අවාසි වලින් එකකි wsl.exe - පැතිකඩ පටවා නැති බව, එබැවින් මෙම විකල්ප පෙරනිමියෙන් ලබා ගත නොහැක (i.e. 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.
  • අපි සෑම විධානයක්ම ස්වයංක්‍රීය සම්පූර්ණ කිරීම සඳහා භාවිතා කරන ෂෙල් ශ්‍රිතයට සිතියම්ගත කරමු (ස්වයංක්‍රීය සම්පූර්ණ කිරීමේ පිරිවිතරයන් අර්ථ දැක්වීමට, බාෂ් භාවිතයන් $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 ස්වයංක්‍රීය සම්පුර්ණ කිරීම ඇති බැවින්, ඔබට ලිනක්ස් මාර්ග සෘජුවම PowerShell තුළ ස්වයංක්‍රීයව සම්පූර්ණ කළ හැක!

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

bash ස්වයංක්‍රීය සම්පුර්ණ කිරීම කිසිදු ප්‍රතිඵලයක් නොලබන අවස්ථා වලදී, PowerShell පද්ධතිය පෙරනිමි වින්ඩෝස් මාර්ග වෙත ප්‍රතිවර්තනය කරයි. මේ අනුව, ප්‍රායෝගිකව, ඔබට ඔබේ අභිමතය පරිදි මාර්ග දෙකම එකවර භාවිතා කළ හැකිය.

නිගමනය

PowerShell සහ WSL භාවිතා කරමින්, අපට Linux විධානයන් Windows වෙත දේශීය යෙදුම් ලෙස ඒකාබද්ධ කළ හැකිය. Win32 builds හෝ Linux උපයෝගිතා සෙවීමට හෝ Linux shell එකකට යාමෙන් ඔබේ වැඩ ප්‍රවාහයට බාධා කිරීමට අවශ්‍ය නැත. යන්තම් WSL ස්ථාපනය කරන්න, වින්‍යාස කරන්න PowerShell පැතිකඩ и ඔබට ආයාත කිරීමට අවශ්‍ය විධාන ලැයිස්තුගත කරන්න! ලිනක්ස් සහ වින්ඩෝස් විධාන පරාමිති සහ ගොනු මාර්ග සඳහා පොහොසත් ස්වයංක්‍රීය සම්පූර්ණ කිරීම අද ස්වදේශීය වින්ඩෝස් විධානවල පවා නොමැති ක්‍රියාකාරීත්වයකි.

ඉහත විස්තර කර ඇති සම්පූර්ණ මූලාශ්‍ර කේතය මෙන්ම එය ඔබගේ කාර්ය ප්‍රවාහයට ඇතුළත් කිරීම සඳහා අමතර මාර්ගෝපදේශ තිබේ මෙහි.

ඔබට වඩාත්ම ප්‍රයෝජනවත් වන්නේ කුමන Linux විධානද? වින්ඩෝස් හි වැඩ කරන විට නැති වූ වෙනත් පොදු දේවල් මොනවාද? අදහස් හෝ ලියන්න GitHub මත!

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න