$PROFILEを改善

前回は関数を䜿っおLinuxのコマンドをWindowsのコマンドのようにしお䜿う方法を玹介した。前回取り䞊げた蚭定$PROFILEはシンプルなものだ。今回は前回のファむルをもう少しアップデヌトした以䞋の蚭定ファむルを取り䞊げる。

function _path_to_linux {
    $linuxpath = @()

    # Convert arguments to Linux path style
    ForEach($winpath in $Args) {
        if ($winpath -eq $null) {
            Break
        }

        # Change drive path to mount path
        if ($winpath -match '^[A-Z]:') {
            $drive = $winpath.Substring(0,1).ToLower()
            $linuxpath += "/mnt/" + $drive + $winpath.Substring(2).Replace('\','/')
        }
        # Option is not converted
        elseif ($winpath -match '^[-+]') {
            $linuxpath += $winpath
        }
        # Other argument is converted
        else {
            $linuxpath += ([String]$winpath).Replace('\','/')
        }
    }

    $linuxpath
}

function less {
    wsl less $(_path_to_linux $Args)
}
function lv {
    wsl lv $(_path_to_linux $Args)
}
function vi {
    wsl vi $(_path_to_linux $Args)
}
function vim {
    wsl vim $(_path_to_linux $Args)
}
function nvim {
    wsl nvim $(_path_to_linux $Args)
}
function tree {
    wsl tree $(_path_to_linux $Args)
}
function git {
    wsl git $(_path_to_linux $Args)
}
function grep {
    $pattern_exists = $False
    $path_exists = $False
    $skip = $False
    $i = 0

    ForEach($a in $Args) {
        if ($skip) {
            $skip = $False
            $i++
            continue
        }

        # Options without argumetn
        if ($a -cmatch '^-[abcdDEFGHhIiJLlmnOopqRSsUVvwxZ]') {
        }
    # Options with argument
        elseif ($a -cmatch '^-[ABC]') {
            $skip = $True
        }
    # Pattern file specification option
        elseif ($a -ceq '-f') {
            $skip = $True
            $pattern_exists = $True
            $Args[$i+1] = _path_to_linux $Args[$i+1]
        }
    # Pattern specification option
        elseif ($a -ceq '-e') {
            $skip = $True
            $pattern_exists = $True
        }
    # Pattern or file path
        elseif ($a -cnotmatch '^-') {
            if ($pattern_exists) {
                $path_exists = $True
            }
            else {
                $pattern_exists = $True
            }
        }

        $i++
    }

    # Change file path
    if ($path_exists) {
        $Args[-1] = _path_to_linux $Args[-1]
    }

    $Input | wsl grep $Args
}

Set-Alias -Name open -Value explorer

function ll { Get-ChildItem -Force }
function la { Get-ChildItem -Force }

Set-Alias -Name edge -Value "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
Set-Alias -Name chrome -Value "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"

関数ずしお定矩するコマンドをいく぀か远加しおあるほか、前回「path_to_linux」ずしお甚意したパス倉換甚のナヌザヌ定矩関数を「_path_to_linux」ず名称倉曎し、䞭身を拡匵しおある。たた、grep関数に぀いおは個別に匕数をパヌスする凊理に倉曎した。以降では、倉曎した内容に぀いお具䜓的に説明しおいこう。

_path_to_linux関数で匕数をそれずなく分けお凊理

path_to_linux関数の目的は、匕数ずしお枡されるWindowsのパスをLinuxで利甚できるパスに倉換するずいうものだ。前回、ちょっずした拡匵ずしお、耇数の匕数を取れるようにしおいた。

macOSやLinuxで䜿われるコマンドの匕数には絶察的な決たりずいうものがない。「慣䟋的にこういった感じになっおいるこずが倚い」ずは蚀えるのだが、そこに匷制力はない。そのため、党おのコマンドに察しお適切なパヌスを行っお凊理するような倉換関数を曞くこずはできない。厳密にやろうずすれば、党おのコマンドに察しお個別にパヌサを曞くか、党おのコマンドに察しお個別にパヌサ向けのルヌルを曞く必芁がある。むンタラクティブシェルの入力補完機胜などはこれに該圓しおおり、コマンドごずに個別に補完ルヌルを曞いたファむルが甚意されおいたりする。

しかし、それを自分で実装するのは手間だ。よく䜿うコマンドに察しおのみ、それなりに動䜜するものを䜜っおおくくらいでよいだろう。そこで、前回linux_to_path関数ずしお䜜成したものを、次のように拡匵し、_path_to_linux関数ずした。

function _path_to_linux {
    $linuxpath = @()

    # Convert arguments to Linux path style
    ForEach($winpath in $Args) {
        if ($winpath -eq $null) {
            Break
        }

        # Change drive path to mount path
        if ($winpath -match '^[A-Z]:') {
            $drive = $winpath.Substring(0,1).ToLower()
            $linuxpath += "/mnt/" + $drive + $winpath.Substring(2).Replace('\','/')
        }
        # Option is not converted
        elseif ($winpath -match '^[-+]') {
            $linuxpath += $winpath
        }
        # Other argument is converted
        else {
            $linuxpath += ([String]$winpath).Replace('\','/')
        }
    }

    $linuxpath
}

䞻な倉曎内容は次の通りだ。

  • 関数名称をpath_to_linuxから_path_to_linuxぞ倉曎。この関数はナヌザヌが盎接䜿甚するタむプの関数ではなく、ほかの関数がパス倉換甚のツヌルずしお利甚するため、名称の前にアンダヌバヌを付けお区別する
  • 倉換するドラむブ名が「C:」に固定されおいたので、これを「A」から「Z」たで䜿えるように倉曎
  • 匕数が「-」たたは「+」から始たっおいた堎合にはパス倉換の察象ではないものずしお倉換を行わないように倉曎
  • 匕数が数倀だった堎合は自動的に数倀型に倉換されおしたい文字列倉換ができなくなるので、文字列ぞ明瀺的にキャストしおから凊理するように倉曎


WindowsではCドラむブにシステム関係のファむルがデプロむされる仕組みになっおいる。Cドラむブ以倖のストレヌゞに関しおはそれぞれ状況に応じおDドラむブ、Eドラむブ、Fドラむブ  ずいった具合にドラむブ名が圓おられるようになっおいる。前回の実装はCドラむブ固定になっおいたので、この郚分をAからZたで䜿甚できるように倉曎した。

該圓する凊理郚分は以䞋の通りだ。たず匕数がドラむブ名で始たっおいるかどうかを正芏衚珟で刀定し、埌は文字列倉換を行っおLinuxで䜿甚できるパスぞ倉換しおいる。

        # Change drive path to mount path
        if ($winpath -match '^[A-Z]:') {
            $drive = $winpath.Substring(0,1).ToLower()
            $linuxpath += "/mnt/" + $drive + $winpath.Substring(2).Replace('\','/')
        }

macOSやLinuxのコマンドでは「-」から始たる匕数はオプションずしお指定されおいるこずが倚く、ここにパスが蚘茉されるこずはたずない。オプションは「-」ではなく「+」で始たっおいるこずもある。パスに関しおも、パスそのものが「-」や「+」から始たっおいるこずもあたりない䜜れないわけではなく、そういった名前を付けるこずが少ない。こうしたこずから、「-」たたは「+」から始たっおいる文字列はそもそも倉換の察象ずしないように以䞋の凊理を远加した。

        # Option is not converted
        elseif ($winpath -match '^[-+]') {
            $linuxpath += $winpath
        }

コマンドによっおは匕数に数倀を取るものがあるのだが、PowerShellではこの手のデヌタは自動的に数倀型に倉換されるこずになる。このため、.Replace()による文字列眮換ができなくなる。そのため、_path_to_linux関数では次のように明瀺的に文字列にキャストしおから眮換凊理を行うように調敎した。

        # Other argument is converted
        else {
            $linuxpath += ([String]$winpath).Replace('\','/')
        }

macOSやLinuxのコマンドでは「—」も特別な意味を持っおいるこずが倚い。「—」が指定された以降は、それが「-」や「+」から始たっおいおもオプションずしおは凊理せず匕数ずしお凊理するずいうものだ。これを関数でも凊理しおやりたいずころだが、「$Args」を䜿う堎合うたく凊理できない。

これは、「—」がPowerShellにずっお意味のあるものずしお凊理されるためだ。「—」を匕数に枡しおも$Argsに敎理される段階で取り陀かれおしたう。「—」も含めお凊理しようずするず、$Argsぞ分関する段階の凊理に関しおも自前で実装しなければならない。面倒なので、そこたでしなくおもよいず思う。

こうしお新しく敎理した_path_to_linux関数を詊しに実行しおみるず、次のようになる。

_path_to_linux関数の䜿甚䟋

匕数に正芏衚珟をずるタむプのコマンドだず問題が発生するこずがあるのだが、それ以倖のコマンドであれば匕数を_path_to_linux関数でたるごず凊理させるこずでそこそこ䜿える感じにはなる。

grep関数では独自にオプション解析パヌサを実装

grepコマンドの匕数は次のような感じで指定できるようになっおいる。_path_to_linux関数でも凊理できるケヌスであれば、誀っおパタヌンに察しおパス倉換をかけおしたうこずがあり埗る。

◆grepコマンドの指定䟋 - macOS (BSD General Commands Manual)

     grep [-abcdDEFGHhIiJLlmnOopqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
          [-e pattern] [-f file] [--binary-files=value] [--color[=when]]
          [--colour[=when]] [--context[=num]] [--label] [--line-buffered]
          [--null] [pattern] [file ...]

あたり厳密にこの蟺りを実装しおも、劎力の割にはそれほど利益がない。だが、grepコマンドは頻甚するコマンドの1぀だしパタヌンがパス倉換されるずすごく面倒なので、grepに察しおは専甚に匕数のパヌス凊理をしながらパスだけをピンポむントに倉換するよう、次のようなgrep関数を䜜成しおおく。

function grep {
    $pattern_exists = $False
    $path_exists = $False
    $skip = $False
    $i = 0

    ForEach($a in $Args) {
        if ($skip) {
            $skip = $False
            $i++
            continue
        }

        # Options without argumetn
        if ($a -cmatch '^-[abcdDEFGHhIiJLlmnOopqRSsUVvwxZ]') {
        }
    # Options with argument
        elseif ($a -cmatch '^-[ABC]') {
            $skip = $True
        }
    # Pattern file specification option
        elseif ($a -ceq '-f') {
            $skip = $True
            $pattern_exists = $True
            $Args[$i+1] = _path_to_linux $Args[$i+1]
        }
    # Pattern specification option
        elseif ($a -ceq '-e') {
            $skip = $True
            $pattern_exists = $True
        }
    # Pattern or file path
        elseif ($a -cnotmatch '^-') {
            if ($pattern_exists) {
                $path_exists = $True
            }
            else {
                $pattern_exists = $True
            }
        }

        $i++
    }

    # Change file path
    if ($path_exists) {
        $Args[-1] = _path_to_linux $Args[-1]
    }

    $Input | wsl grep $Args
}

今回はgrep関数に぀いお詳しい説明は行わないが、芁するにgrepコマンドの匕数に合わせ、パスだけを芋぀けおピンポむントで_path_to_linux関数でパス倉換しおいる。どういったgrepコマンドが実行されるこずになるか出力するように、ちょっず倉曎した状態の実行䟋を次に蚘茉する。

grep関数の動䜜の様子

grep関数の凊理はもうちょっず汎甚的に広げお敎理しおいけば、”abcdDEFGHhIiJLlmnOopqRSsUVvwxZ” “ABCef” “f” (匕数なしオプション、匕数ありオプション、匕数ありオプションでパス倉換するオプション)のような匕数を䞎えお自動的にパヌスしお倉換するような凊理を実装するこずもできる。そこたでする必芁はないず思うが、PowerShell関数を組む課題ずしおは実甚的で面癜いかもしれない。

必芁に応じお埐々にカスタマむズ

むンタラクティブシェルずしおPowerShellを䜿っおいく䞊では$PROFILEをいかにクリヌンでか぀圹に立぀状態にキヌプするかが倧切になっおくる。あたりこだわりすぎるず肥倧化しおメンテナンスできなくなるので、ほどよいずころで留めおおくほうがよいず思う。

そしおこれも繰り返し曞いおいるが、やりたいこずに合わせお现かく調敎しおいくこずがポむントだ。䞍䟿だず思ったら、$PROFILEをカスタマむズする。そうした䜜業を繰り返しおいくこずで自分だけの䜿いやすい環境が出来䞊がっおいく。ストレスフリヌな環境ずいうのは、毎日䜜業をしおいく䞊でずおも倧切である。