PowerShell ๋ฐ WSL์„ ์‚ฌ์šฉํ•˜์—ฌ Linux ๋ช…๋ น์„ Windows์— ํ†ตํ•ฉ

Windows ๊ฐœ๋ฐœ์ž์˜ ์ผ๋ฐ˜์ ์ธ ์งˆ๋ฌธ: โ€œ์™œ ์•„์ง๋„ <ะ’ะกะขะะ’ะฌะขะ• ะขะฃะข ะ›ะฎะ‘ะ˜ะœะฃะฎ ะšะžะœะะะ”ะฃ LINUX>?. ๊ฐ•๋ ฅํ•œ ์Šค์™€์ดํ”„์ธ์ง€ less ๋˜๋Š” ์ต์ˆ™ํ•œ ๋„๊ตฌ grep ๋˜๋Š” sed, Windows ๊ฐœ๋ฐœ์ž๋Š” ์ผ์ƒ ์—…๋ฌด์—์„œ ์ด๋Ÿฌํ•œ ๋ช…๋ น์— ์‰ฝ๊ฒŒ ์•ก์„ธ์Šคํ•˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.

Linux์šฉ Windows ํ•˜์œ„ ์‹œ์Šคํ…œ(WSL) ์ด ์ ์—์„œ ํฐ ์ง„์ „์„ ์ด๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Windows์—์„œ Linux ๋ช…๋ น์„ ํ”„๋ก์‹œํ•˜์—ฌ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. wsl.exe (์˜ˆ : wsl ls). ์ด๋Š” ์ƒ๋‹นํ•œ ๊ฐœ์„ ์ด๊ธฐ๋Š” ํ•˜์ง€๋งŒ, ์ด ์˜ต์…˜์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์œ ๋น„์ฟผํ„ฐ์Šค ์ถ”๊ฐ€ wsl ์ง€๋ฃจํ•˜๊ณ  ๋ถ€์ž์—ฐ ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.
  • ๋ฐฑ์Šฌ๋ž˜์‹œ๊ฐ€ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ๋ถ„ ๊ธฐํ˜ธ๊ฐ€ ์•„๋‹Œ ์ด์Šค์ผ€์ดํ”„ ๋ฌธ์ž๋กœ ํ•ด์„๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ธ์ˆ˜์˜ Windows ๊ฒฝ๋กœ๊ฐ€ ํ•ญ์ƒ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.
  • ์ธ์ˆ˜์˜ Windows ๊ฒฝ๋กœ๋Š” WSL์˜ ํ•ด๋‹น ํƒ‘์žฌ ์ง€์ ์œผ๋กœ ๋ณ€ํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ณ„์นญ ๋ฐ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” WSL ํ”„๋กœํ•„์—์„œ๋Š” ๊ธฐ๋ณธ ์„ค์ •์ด ์กด์ค‘๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • Linux ๊ฒฝ๋กœ ์™„์„ฑ์€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ช…๋ น ์™„์„ฑ์€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ธ์ˆ˜ ์™„์„ฑ์€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ Linux ๋ช…๋ น์€ Windows์—์„œ XNUMX๋“ฑ๊ธ‰ ์‹œ๋ฏผ์ฒ˜๋Ÿผ ์ทจ๊ธ‰๋˜๋ฉฐ ๊ธฐ๋ณธ ๋ช…๋ น๋ณด๋‹ค ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์˜ ๊ถŒ๋ฆฌ๋ฅผ ๊ท ๋“ฑํ™”ํ•˜๋ ค๋ฉด ๋‚˜์—ด๋œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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, ๊ธฐ๋ณธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์ง€๋งŒ cmdlet ๋ฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์—๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์…ธ์—์„œ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋กœ ์ธํ•ด ๋ถˆํ•„์š”ํ•œ ๋ณต์žก์„ฑ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: 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. ๋ฐฐ์‰ฌ๋Š” ๊ฐ•๋ ฅํ•˜๋‹ค ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐ€๋Šฅํ•œ ์ž๋™ ์™„์„ฑ ๋„๊ตฌ. 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 ์ž๋™ ์™„์„ฑ ๊ธฐ๋Šฅ์ด ์žˆ์œผ๋ฏ€๋กœ PowerShell์—์„œ ์ง์ ‘ Linux ๊ฒฝ๋กœ๋ฅผ ์ž๋™ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

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

Bash ์ž๋™ ์™„์„ฑ์œผ๋กœ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ PowerShell์€ ์‹œ์Šคํ…œ ๊ธฐ๋ณธ Windows ๊ฒฝ๋กœ๋กœ ๋˜๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‹ค์ œ๋กœ๋Š” ์žฌ๋Ÿ‰์— ๋”ฐ๋ผ ๋‘ ๊ฒฝ๋กœ๋ฅผ ๋™์‹œ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

PowerShell๊ณผ WSL์„ ์‚ฌ์šฉํ•˜๋ฉด Linux ๋ช…๋ น์„ ๊ธฐ๋ณธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ Windows์— ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Win32 ๋นŒ๋“œ ๋˜๋Š” Linux ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ฑฐ๋‚˜ Linux ์…ธ๋กœ ์ด๋™ํ•˜์—ฌ ์ž‘์—… ํ๋ฆ„์„ ์ค‘๋‹จํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ WSL ์„ค์น˜, ๊ตฌ์„ฑ ํŒŒ์›Œ์…ธ ํ”„๋กœํ•„ ะธ ๊ฐ€์ ธ์˜ค๋ ค๋Š” ๋ช…๋ น์„ ๋‚˜์—ดํ•˜์‹ญ์‹œ์˜ค.! Linux ๋ฐ Windows ๋ช…๋ น ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ํŒŒ์ผ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ํ’๋ถ€ํ•œ ์ž๋™ ์™„์„ฑ ๊ธฐ๋Šฅ์€ ํ˜„์žฌ ๊ธฐ๋ณธ Windows ๋ช…๋ น์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

์œ„์— ์„ค๋ช…๋œ ์ „์ฒด ์†Œ์Šค ์ฝ”๋“œ์™€ ์ด๋ฅผ ์›Œํฌํ”Œ๋กœ์— ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€ ์ง€์นจ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—.

์–ด๋–ค Linux ๋ช…๋ น์ด ๊ฐ€์žฅ ์œ ์šฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”? Windows์—์„œ ์ž‘์—…ํ•  ๋•Œ ๋ˆ„๋ฝ๋œ ๋‹ค๋ฅธ ์ผ๋ฐ˜์ ์ธ ์‚ฌํ•ญ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋Œ“๊ธ€๋กœ ์ ์–ด์ฃผ์‹œ๊ฑฐ๋‚˜ GitHub์—์„œ!

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€