PowerShell ۽ WSL استعمال ڪندي ونڊوز ۾ لينڪس حڪمن کي ضم ڪرڻ

ونڊوز ڊولپرز کان هڪ عام سوال: "ڇو اڃا تائين ناهي <ВСТАВЬТЕ ТУТ ЛЮБИМУЮ КОМАНДУ LINUX>؟. ڇا اهو هڪ طاقتور سوائپ آهي less يا واقف اوزار grep يا sed، ونڊوز ڊولپرز پنهنجي روزاني ڪم ۾ انهن حڪمن تائين آسان رسائي چاهين ٿا.

لينڪس لاءِ ونڊوز سب سسٽم (WSL) ان سلسلي ۾ هڪ وڏو قدم کنيو آهي. اهو توهان کي اجازت ڏئي ٿو ته لينڪس ڪمانڊ کي ونڊوز مان پراکسي ڪندي ڪال ڪري wsl.exe (مثال طور. wsl ls). جيتوڻيڪ هي هڪ اهم سڌارو آهي، هي اختيار ڪيترن ئي نقصانن جو شڪار آهي.

  • عام اضافو wsl تڪليف ڏيندڙ ۽ غير فطري.
  • دليلن ۾ ونڊوز رستا هميشه ڪم نه ڪندا آهن ڇو ته بيڪ سليشس کي ڊاريڪٽري ڌار ڪرڻ جي بجاءِ فرار ڪردارن جي طور تي تفسير ڪيو ويندو آهي.
  • دليلن ۾ ونڊوز رستا WSL ۾ لاڳاپيل مائونٽ پوائنٽ ڏانهن ترجمو نه ڪيا ويا آهن.
  • ڊفالٽ سيٽنگون WSL پروفائلز ۾ عرف ۽ ماحوليات جي متغيرن سان عزت نه آھن.
  • لينڪس رستي جي مڪمل ٿيڻ جي حمايت نه ڪئي وئي آهي.
  • ڪمانڊ مڪمل ڪرڻ جي حمايت نه ڪئي وئي آهي.
  • دليل جي مڪمل ٿيڻ جي حمايت نه ڪئي وئي آهي.

نتيجي طور، لينڪس حڪمن کي ونڊوز جي تحت سيڪنڊ-ڪلاس شهرين وانگر علاج ڪيو ويندو آهي- ۽ مقامي حڪمن کان وڌيڪ استعمال ڪرڻ ڏکيو آهي. انهن جي حقن کي برابر ڪرڻ لاء، اهو ضروري آهي ته فهرستن جي مسئلن کي حل ڪيو وڃي.

پاور شيل فنڪشن ريپرس

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. Bash طاقتور آهي پروگرام قابل خودڪار مڪمل ڪرڻ جا اوزار. WSL توهان کي پاور شيل مان بش ڪال ڪرڻ جي اجازت ڏئي ٿي. جيڪڏهن اسان پنهنجي پاور شيل فنڪشن ريپرز لاءِ دليلن جي مڪمل ٿيڻ کي رجسٽر ڪري سگھون ٿا ۽ مڪمل ڪرڻ لاءِ ڪال 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]
    }
}

ڪوڊ بش جي اندروني ڪمن مان ڪجھ سمجھڻ کان سواء ٿورڙو گندو آھي، پر بنيادي طور تي جيڪو اسين ڪندا آھيون اھو آھي:

  • اسان جي سڀني فنڪشن ريپرز لاءِ هڪ دليل مڪمل ڪندڙ رجسٽر ڪرڻ هڪ لسٽ پاس ڪندي $commands پيٽرول ۾ -CommandName لاء Register-ArgumentCompleter.
  • اسان هر ڪمانڊ کي شيل فنڪشن ۾ نقشي ڪريون ٿا جيڪو بش استعمال ڪري ٿو خودڪار مڪمل ڪرڻ لاءِ (خود مڪمل ڪرڻ جي وضاحتن کي بيان ڪرڻ لاءِ، بش استعمال $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 سسٽم جي ڊفالٽ ونڊوز رستن ڏانهن موٽائي ٿو. اهڙيء طرح، عملي طور تي، توهان پنهنجي صوابديد تي ٻنهي طريقن سان گڏ استعمال ڪري سگهو ٿا.

ٿڪل

PowerShell ۽ WSL استعمال ڪندي، اسان لينڪس حڪمن کي ونڊوز ۾ مقامي ايپليڪيشنن جي طور تي ضم ڪري سگھون ٿا. Win32 تعميرات يا لينڪس يوٽيلٽيز کي ڳولڻ جي ڪا ضرورت ناهي يا لينڪس شيل ڏانهن وڃڻ سان توهان جي ڪم جي فلو کي مداخلت ڪرڻ جي ضرورت ناهي. بس WSL انسٽال ڪريو، ترتيب ڏيڻ PowerShell پروفائل и انھن حڪمن کي لسٽ ڪريو جيڪي توھان درآمد ڪرڻ چاھيو ٿا! لينڪس ۽ ونڊوز ڪمانڊ پيرا ميٽرز ۽ فائل رستا لاءِ رچ خودڪار مڪمل ڪارڪردگي آهي جيڪا اڄ به مقامي ونڊوز ڪمانڊز ۾ موجود ناهي.

مٿي بيان ڪيل مڪمل سورس ڪوڊ، انهي سان گڏ اضافي هدايتون ان کي توهان جي ڪم فلو ۾ شامل ڪرڻ لاءِ، موجود آهي هتي.

ڪھڙا لينڪس ڪمانڊ توھان کي تمام گھڻو مفيد ملندا آھن؟ ونڊوز ۾ ڪم ڪرڻ وقت ڪهڙيون ٻيون عام شيون غائب آهن؟ تبصرن ۾ لکو يا GitHub تي!

جو ذريعو: www.habr.com

تبصرو شامل ڪريو