PowerShell እና WSL በመጠቀም የሊኑክስ ትዕዛዞችን ወደ ዊንዶውስ ማዋሃድ

የተለመደ ጥያቄ ከዊንዶውስ ገንቢዎች: "ለምን አሁንም የለም <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>? ኃይለኛ ማንሸራተት ይሁን less ወይም የታወቁ መሳሪያዎች grep ወይም sed, የዊንዶውስ ገንቢዎች በዕለት ተዕለት ሥራቸው ውስጥ እነዚህን ትዕዛዞች በቀላሉ ማግኘት ይፈልጋሉ.

የዊንዶውስ ንዑስ ስርዓት ለሊኑክስ (WSL) በዚህ ረገድ ትልቅ እርምጃ ወስዷል። የሊኑክስ ትዕዛዞችን ከዊንዶውስ በመወከል እንዲደውሉ ይፈቅድልዎታል። wsl.exe (ለምሳሌ, wsl ls). ምንም እንኳን ይህ ጉልህ የሆነ ማሻሻያ ቢሆንም, ይህ አማራጭ በበርካታ ድክመቶች ይሠቃያል.

  • በየቦታው መጨመር wsl አሰልቺ እና ተፈጥሯዊ ያልሆነ.
  • በክርክር ውስጥ ያሉ የዊንዶውስ ዱካዎች ሁልጊዜ አይሰሩም ምክንያቱም የኋላ ሽፋኖች ከማውጫ መለያዎች ይልቅ እንደ ማምለጫ ገጸ-ባህሪያት ይተረጎማሉ።
  • በክርክር ውስጥ ያሉ የዊንዶውስ ዱካዎች በ WSL ውስጥ ወደሚገኘው ተጓዳኝ ተራራ ነጥብ አልተተረጎሙም።
  • ነባሪ ቅንጅቶች በWSL መገለጫዎች ተለዋጭ ስሞች እና የአካባቢ ተለዋዋጮች ውስጥ አይከበሩም።
  • የሊኑክስ መንገድ ማጠናቀቅ አይደገፍም።
  • የትእዛዝ ማጠናቀቅ አይደገፍም።
  • የክርክር ማጠናቀቅ አይደገፍም።

በውጤቱም፣ የሊኑክስ ትዕዛዞች በዊንዶውስ ስር እንደ ሁለተኛ ደረጃ ዜጎች ተደርገው ይወሰዳሉ - እና ከአገርኛ ትዕዛዞች ይልቅ ለመጠቀም በጣም ከባድ ናቸው። መብቶቻቸውን እኩል ለማድረግ የተዘረዘሩትን ችግሮች መፍታት አስፈላጊ ነው.

PowerShell ተግባር wrappers

በPowerShell ተግባር መጠቅለያዎች፣ የትዕዛዝ ማጠናቀቂያ ማከል እና የቅድመ ቅጥያዎችን አስፈላጊነት ማስወገድ እንችላለን wsl, የዊንዶውስ መንገዶችን ወደ WSL ዱካዎች መተርጎም. ለዛጎሎች መሰረታዊ መስፈርቶች

  • ለእያንዳንዱ ሊኑክስ ትዕዛዝ አንድ አይነት ስም ያለው አንድ የተግባር መጠቅለያ መኖር አለበት።
  • ዛጎሉ ያለፉትን የዊንዶውስ መንገዶች እንደ ክርክር አውቆ ወደ WSL ዱካዎች መለወጥ አለበት።
  • ቅርፊቱ መደወል አለበት wsl በተገቢው የሊኑክስ ትእዛዝ ወደ ማንኛውም የቧንቧ መስመር ግቤት እና ማንኛውንም የትዕዛዝ መስመር ክርክሮችን ወደ ተግባሩ በማለፍ.

ይህ ስርዓተ-ጥለት በማንኛውም ትዕዛዝ ላይ ሊተገበር ስለሚችል, የእነዚህን መጠቅለያዎች ፍቺ ማጠቃለል እና ከውጭ ለማስመጣት ከትእዛዞች ዝርዝር ውስጥ በተለዋዋጭ ማመንጨት እንችላለን.

# 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 የቧንቧ መስመር ግቤት እና ማንኛውም የትዕዛዝ መስመር ክርክሮች.

በእነዚህ መጠቅለያዎች ቅድመ ቅጥያ ሳይጨምሩ የሚወዱትን የሊኑክስ ትዕዛዞችን በተፈጥሯዊ መንገድ መደወል ይችላሉ። 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. የተለየ የሃሽ ሰንጠረዥ ተጨማሪ ጥቅም የማሰናከል ችሎታ ነው $WslDefaultParameterValues በተናጠል ከ $PSDefaultParameterValues.

የክርክር ማጠናቀቅ

PowerShell ትዕዛዙን በመጠቀም የክርክር የፊልም ማስታወቂያዎችን እንዲመዘግቡ ይፈቅድልዎታል። Register-ArgumentCompleter. ባሽ ሃይል አለው። ፕሮግራም ሊደረግ የሚችል ራስ-ማጠናቀቂያ መሳሪያዎች. WSL ከPowerShell ወደ bash እንዲደውሉ ይፈቅድልዎታል። ለፓወር ሼል ተግባር መጠቅለያዎች የክርክር ማጠናቀቂያዎችን መመዝገብ ከቻልን እና ማጠናቀቂያዎቹን ለማመንጨት 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 በመለኪያ -CommandNameRegister-ArgumentCompleter.
  • እያንዳንዱን ትዕዛዝ ባሽ ለራስ-ማጠናቀቂያ የሚጠቀመውን የሼል ተግባር (የራስ-አጠናቅቅ ዝርዝሮችን ለመግለጽ፣ bash ይጠቀማል) እናቀርባለን። $F, ምህጻረ ቃል ለ complete -F <FUNCTION>).
  • የPowerShell ክርክሮችን በመቀየር ላይ $wordToComplete, $commandAst и $cursorPosition እንደ መግለጫው በ bash አውቶማቲክ ማጠናቀቂያ ተግባራት በሚጠበቀው ቅርጸት ፕሮግራም ሊደረግ የሚችል ራስ-ማጠናቀቅ ባሽ
  • ለማዘዋወር የትእዛዝ መስመር አዘጋጅተናል wsl.exe, አካባቢው በትክክል መዘጋጀቱን ያረጋግጣል, ተገቢውን ራስ-ማጠናቀቅ ተግባር ይጠራል እና ውጤቱን በመስመር-በ-መስመር ፋሽን ያስወጣል.
  • ከዚያም እንጠራዋለን wsl ከትዕዛዝ መስመሩ ጋር ውጤቱን በመስመር መለያዎች እንለያለን እና ለእያንዳንዱ እንፈጥራለን CompletionResults፣ እነሱን መደርደር እና እንደ ክፍተቶች እና ቅንፍ ያሉ ገጸ-ባህሪያትን ማምለጥ አለበለዚያ በተሳሳተ መንገድ ይተረጎማሉ።

በዚህ ምክንያት የእኛ የሊኑክስ ትዕዛዝ ዛጎሎች ልክ እንደ ባሽ ተመሳሳይ አውቶማቲክን ይጠቀማሉ! ለምሳሌ:

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

እያንዳንዱ አውቶማቲክ ማጠናቀቂያ ለቀድሞው ነጋሪ እሴት የተወሰኑ እሴቶችን ያቀርባል ፣ እንደ የ WSL የታወቁ አስተናጋጆች ያሉ የውቅር ውሂብን ያንብቡ!

<TAB> መለኪያዎች በኩል ዑደት ይሆናል. <Ctrl + пробел> ያሉትን አማራጮች ሁሉ ያሳያል።

በተጨማሪም፣ አሁን የባሽ አውቶማቲክ ማጠናቀቂያ ስላለን፣ የሊኑክስ መንገዶችን በቀጥታ በPowerShell ውስጥ በራስ ሰር ማጠናቀቅ ይችላሉ።

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

ባሽ አውቶማቲክ ማጠናቀቅ ምንም ውጤት ባያመጣበት ጊዜ፣ PowerShell ወደ ስርዓቱ ነባሪ የዊንዶውስ ዱካዎች ይመለሳል። ስለዚህ፣ በተግባር፣ እንደ ምርጫዎ ሁለቱንም መንገዶች በአንድ ጊዜ መጠቀም ይችላሉ።

መደምደሚያ

PowerShell እና WSL ን በመጠቀም የሊኑክስ ትዕዛዞችን ወደ ዊንዶውስ እንደ ቤተኛ አፕሊኬሽኖች ማዋሃድ እንችላለን። የዊን32 ግንባታዎችን ወይም የሊኑክስ መገልገያዎችን መፈለግ ወይም ወደ ሊኑክስ ሼል በመሄድ የስራ ሂደትዎን ማቋረጥ አያስፈልግም። ልክ WSL ን ጫን, አዋቅር የPowerShell መገለጫ и ለማስመጣት የሚፈልጓቸውን ትዕዛዞች ይዘርዝሩ! ለሊኑክስ እና ለዊንዶውስ የትዕዛዝ መለኪያዎች እና የፋይል ዱካዎች የበለፀገ አውቶማቲክ ማጠናቀቂያ ዛሬ በቤተኛ የዊንዶውስ ትዕዛዞች እንኳን የማይገኝ ተግባር ነው።

ከላይ የተገለጸው ሙሉ ምንጭ ኮድ፣ እንዲሁም በስራ ሂደትዎ ውስጥ ለማካተት ተጨማሪ መመሪያዎች አሉ። እዚህ.

የትኞቹ የሊኑክስ ትዕዛዞች በጣም ጠቃሚ ሆነው ያገኟቸዋል? በዊንዶውስ ውስጥ ሲሰሩ ምን ሌሎች የተለመዱ ነገሮች ይጎድላሉ? በአስተያየቶቹ ውስጥ ይፃፉ ወይም በ GitHub ላይ!

ምንጭ: hab.com

አስተያየት ያክሉ