「MSYS2」のコマンドプラットフォームとしての仕組みは単純だ。Windowsの環境変数PathにMSYS2のコマンドが収められているパスを追加すれば、それだけで動作する。Windowsとの親和性で問題になるのは、その優先順位だ。

MSYS2のコマンドを使うことを最優先させるなら、WindowsのコマンドパスよりもMSYS2のコマンドパスを優先的に環境変数Pathに登録すればよい。しかし、これでは逆にWindowsのコマンドを優先的に動作させなければならない状況で問題が出る。PowerShellのようなWindowsのシェルを使いつつもMSYS2のコマンド群を優先的に使いたいのであれば、この状況を静的に解決する方法はほとんどない。

ただし、動的に解決する方法ならある。MSYS2に寄せた設定と、Windowsに寄せた設定を動的に切り替える方法だ。このやり方ならば、必要に応じてスイッチするだけでニーズを満たせる。WindowsのシェルでMSYS2を使いこなしてくなら、これが現実的な解答ではないだろうか。

MSYS2へ寄せる

次のような設定を$PROFILE (PowerShellの設定ファイルのパスが収められた変数)のファイルへ書き込んでおくと、PowreShellで動くコマンドがMSYS2最優先になる。

function mode_msys2 {
        # MSYS2のコマンドパスを最優先に入れ替える
        $sshpath = "C:\WINDOWS\System32\OpenSSH"
        $msyspath = "C:\msys64\usr\bin"
        $mingw64path = "C:\msys64\mingw64\bin"

        Set-Item Env:Path $env:Path.Replace($sshpath,"")
        Set-Item Env:Path $env:Path.Replace($msyspath,"")
        Set-Item Env:Path $env:Path.Replace($mingw64path,"")

        Set-Item Env:Path "$mingw64path;$env:Path"
        Set-Item Env:Path "$msyspath;$env:Path"
        Set-Item Env:Path "$sshpath;$env:Path"

        # MSYS2コマンドと重複するエイリアスを削除する
        Get-Alias cat > $null 2>&1 && Remove-Alias cat
        Get-Alias cp > $null 2>&1 && Remove-Alias cp
        Get-Alias ls > $null 2>&1 && Remove-Alias ls
        Get-Alias mv > $null 2>&1 && Remove-Alias mv
        Get-Alias rm > $null 2>&1 && Remove-Alias rm
        Get-Alias diff > $null 2>&1 && Remove-Alias -Force diff
        Get-Alias sort > $null 2>&1 && Remove-Alias -Force sort
        Get-Alias tee > $null 2>&1 && Remove-Alias -Force tee

        # ls系短縮コマンドを関数として作成
        function global:ls { C:\msys64\usr\bin\ls.exe --color $Args }
        function global:ll { C:\msys64\usr\bin\ls.exe --color $Args -l }
        function global:la { C:\msys64\usr\bin\ls.exe --color $Args -a }
}
mode_msys2

仕組みは簡単だ。環境変数Pathを編集して、MSYS2のパスを最優先にするだけだ。

まず、次の処理で環境変数Pathから優先順位を変更したいパスを削除する。処理を行う前準備だ。

$sshpath = "C:\WINDOWS\System32\OpenSSH"
$msyspath = "C:\msys64\usr\bin"
$mingw64path = "C:\msys64\mingw64\bin"

Set-Item Env:Path $env:Path.Replace($sshpath,"")
Set-Item Env:Path $env:Path.Replace($msyspath,"")
Set-Item Env:Path $env:Path.Replace($mingw64path,"")

次に、環境変数PathにMSYS2のパスを優先順位高めで追加する。

 Set-Item Env:Path "$mingw64path;$env:Path"
 Set-Item Env:Path "$msyspath;$env:Path"
 Set-Item Env:Path "$sshpath;$env:Path"

1つ注意して欲しいのは、MSYS2を本当に最優先にすると困る事態も出てくるということだ。ここでは、MSYS2よりもWindows OpenSSHの優先順位を上げて再登録している。MSYS2にもOpenSSHは含まれているのだが、Windows OpenSSHを使っている場合にはうまく動かないのだ。こういった状況が判明したら、上記サンプルのようにMSYS2よりもさらに優先順位の高いパスとして環境変数Pathに追加してみてほしい。それで問題が解決するなら万々歳だ。

次に、PowrShellのエイリアスとMSYS2のコマンドがぶつかっていた部分を解決したいので、衝突しているエイリアスを次のように削除する。ここでは、リードオンリーに設定されているエイリアスも強制的に削除している。

 Get-Alias cat > $null 2>&1 && Remove-Alias cat
 Get-Alias cp > $null 2>&1 && Remove-Alias cp
 Get-Alias ls > $null 2>&1 && Remove-Alias ls
 Get-Alias mv > $null 2>&1 && Remove-Alias mv
 Get-Alias rm > $null 2>&1 && Remove-Alias rm
 Get-Alias diff > $null 2>&1 && Remove-Alias -Force diff
 Get-Alias sort > $null 2>&1 && Remove-Alias -Force sort
 Get-Alias tee > $null 2>&1 && Remove-Alias -Force tee

最後の設定はLinuxのシェルのエイリアスの使い方を模したものだ。よく使う短縮コマンドが利用できるように、PowerShellの関数を使って設定を行っている。

function global:ls { C:\msys64\usr\bin\ls.exe --color $Args }
function global:ll { C:\msys64\usr\bin\ls.exe --color $Args -l }
function global:la { C:\msys64\usr\bin\ls.exe --color $Args -a }

仕組みとしてはこれで一通り網羅しているので、後は自分のやりたいことに合わせて書き換えてもらえればと思う。

Windowsへ寄せる

最後に、mode_msys2で書き換えた内容を元に戻す関数を作成しておく。以下のように$PROFILEファイルに書き込んでおけばよい。

function mode_pwsh {
    # MSYS2のコマンドパスを低優先へ入れ替える
    $sshpath = "C:\WINDOWS\System32\OpenSSH"
    $msyspath = "C:\msys64\usr\bin"
    $mingw64path = "C:\msys64\mingw64\bin"

    Set-Item Env:Path $env:Path.Replace($sshpath,"")
    Set-Item Env:Path $env:Path.Replace($msyspath,"")
    Set-Item Env:Path $env:Path.Replace($mingw64path,"")

    Set-Item Env:Path "$env:Path;$sshpath"
    Set-Item Env:Path "$env:Path;$msyspath"
    Set-Item Env:Path "$env:Path;$mingw64path"

    # 作成した関数を削除
    Get-Item Function:ls > $null 2>&1 && Remove-Item Function:ls
    Get-Item Function:ll > $null 2>&1 &&Remove-Item Function:ll
    Get-Item Function:la > $null 2>&1 &&Remove-Item Function:la

    # 削除したエイリアスを元に戻す
    Get-Alias cat > $null 2>&1 || Set-Alias -Name cat -Value Get-Content
    Get-Alias cp > $null 2>&1 || Set-Alias -Name cp -Value Copy-Item
    Get-Alias ls > $null 2>&1 || Set-Alias -Name ls -Value Get-ChildItem
    Get-Alias mv > $null 2>&1 || Set-Alias -Name mv -Value Move-Item
    Get-Alias rm > $null 2>&1 || Set-Alias -Name rm -Value Remove-Item
    Get-Alias diff > $null 2>&1 || Set-Alias -Force -Name diff -Value Compare-Object
    Get-Alias sort > $null 2>&1 || Set-Alias -Force -Name sort -Value Sort-Object -Option ReadOnly
    Get-Alias tee > $null 2>&1 || Set-Alias -Force -Name tee -Value Tee-Object -Option ReadOnly
}

やっていることはMSYS2へ寄せる設定の逆だ。まず、次のようにパスの優先順位を変更するものを環境変数Pathから削除する。

$sshpath = "C:\WINDOWS\System32\OpenSSH"
$msyspath = "C:\msys64\usr\bin"
$mingw64path = "C:\msys64\mingw64\bin"

Set-Item Env:Path $env:Path.Replace($sshpath,"")
Set-Item Env:Path $env:Path.Replace($msyspath,"")
Set-Item Env:Path $env:Path.Replace($mingw64path,"")

次に、MSYS2のパスを優先度低めにして環境変数Pathへ追加する。ここでもWindows OpenSSHのパスはMSYS2のパスよりも優先的にしているところがポイントだ。この辺りは必要に応じて書き換えてもらえればと思う。

Set-Item Env:Path "$env:Path;$sshpath"
Set-Item Env:Path "$env:Path;$msyspath"
Set-Item Env:Path "$env:Path;$mingw64path"

MSYS2へ寄せた設定を行ったときに追加した関数を削除する。

Get-Item Function:ls > $null 2>&1 && Remove-Item Function:ls
Get-Item Function:ll > $null 2>&1 &&Remove-Item Function:ll
Get-Item Function:la > $null 2>&1 &&Remove-Item Function:la

そして最後に削除したPowerShellのエイリアスを復活させて処理は完了だ。

Get-Alias cat > $null 2>&1 || Set-Alias -Name cat -Value Get-Content
Get-Alias cp > $null 2>&1 || Set-Alias -Name cp -Value Copy-Item
Get-Alias ls > $null 2>&1 || Set-Alias -Name ls -Value Get-ChildItem
Get-Alias mv > $null 2>&1 || Set-Alias -Name mv -Value Move-Item
Get-Alias rm > $null 2>&1 || Set-Alias -Name rm -Value Remove-Item
Get-Alias diff > $null 2>&1 || Set-Alias -Force -Name diff -Value Compare-Object
Get-Alias sort > $null 2>&1 || Set-Alias -Force -Name sort -Value Sort-Object -Option ReadOnly
Get-Alias tee > $null 2>&1 || Set-Alias -Force -Name tee -Value Tee-Object -Option ReadOnly

実際に追加する設定まとめ

これらの2つの設定を次のような感じで統合し、ほかに必要な環境変数の設定なども含む状態でまとめると、次のようになる。これを$PROFILEに書き込んでおけば、とりえあずMSYS2寄りのPowerShellの環境が出来上がる。

# MSYS2 Integration
if (Test-Path -PathType Container C:\msys64\) {
    $env:HOME = "C:\Users\${env:USERNAME}"
    $env:LANG = "ja_JP.UTF-8"
    $env:LC_CTYPE = "ja_JP.UTF-8"
    $env:TZ = "Asia/Tokyo"

    function mode_msys2 {
        # MSYS2のコマンドパスを最優先に入れ替える
        $sshpath = "C:\WINDOWS\System32\OpenSSH"
        $msyspath = "C:\msys64\usr\bin"
        $mingw64path = "C:\msys64\mingw64\bin"

        Set-Item Env:Path $env:Path.Replace($sshpath,"")
        Set-Item Env:Path $env:Path.Replace($msyspath,"")
        Set-Item Env:Path $env:Path.Replace($mingw64path,"")

        Set-Item Env:Path "$mingw64path;$env:Path"
        Set-Item Env:Path "$msyspath;$env:Path"
        Set-Item Env:Path "$sshpath;$env:Path"

        # MSYS2コマンドと重複するエイリアスを削除する
        Get-Alias cat > $null 2>&1 && Remove-Alias cat
        Get-Alias cp > $null 2>&1 && Remove-Alias cp
        Get-Alias ls > $null 2>&1 && Remove-Alias ls
        Get-Alias mv > $null 2>&1 && Remove-Alias mv
        Get-Alias rm > $null 2>&1 && Remove-Alias rm
        Get-Alias diff > $null 2>&1 && Remove-Alias -Force diff
        Get-Alias sort > $null 2>&1 && Remove-Alias -Force sort
        Get-Alias tee > $null 2>&1 && Remove-Alias -Force tee

        # ls系短縮コマンドを関数として作成
        function global:ls { C:\msys64\usr\bin\ls.exe --color $Args }
        function global:ll { C:\msys64\usr\bin\ls.exe --color $Args -l }
        function global:la { C:\msys64\usr\bin\ls.exe --color $Args -a }
    }

    function mode_pwsh {
        # MSYS2のコマンドパスを低優先へ入れ替える
        $sshpath = "C:\WINDOWS\System32\OpenSSH"
        $msyspath = "C:\msys64\usr\bin"
        $mingw64path = "C:\msys64\mingw64\bin"

        Set-Item Env:Path $env:Path.Replace($sshpath,"")
        Set-Item Env:Path $env:Path.Replace($msyspath,"")
        Set-Item Env:Path $env:Path.Replace($mingw64path,"")

        Set-Item Env:Path "$env:Path;$sshpath"
        Set-Item Env:Path "$env:Path;$msyspath"
        Set-Item Env:Path "$env:Path;$mingw64path"

        # 作成した関数を削除
        Get-Item Function:ls > $null 2>&1 && Remove-Item Function:ls
        Get-Item Function:ll > $null 2>&1 &&Remove-Item Function:ll
        Get-Item Function:la > $null 2>&1 &&Remove-Item Function:la

        # 削除したエイリアスを元に戻す
        Get-Alias cat > $null 2>&1 || Set-Alias -Name cat -Value Get-Content
        Get-Alias cp > $null 2>&1 || Set-Alias -Name cp -Value Copy-Item
        Get-Alias ls > $null 2>&1 || Set-Alias -Name ls -Value Get-ChildItem
        Get-Alias mv > $null 2>&1 || Set-Alias -Name mv -Value Move-Item
        Get-Alias rm > $null 2>&1 || Set-Alias -Name rm -Value Remove-Item
        Get-Alias diff > $null 2>&1 || Set-Alias -Force -Name diff -Value Compare-Object
        Get-Alias sort > $null 2>&1 || Set-Alias -Force -Name sort -Value Sort-Object -Option ReadOnly
        Get-Alias tee > $null 2>&1 || Set-Alias -Force -Name tee -Value Tee-Object -Option ReadOnly
    }

    mode_msys2
}

Windows寄りの環境が必要になったら「mode_pwsh」と実行して設定を変更する。もう一度MSYS2に寄せた環境に戻したくなったら「mode_msys2」と実行すればよい。これで、mode_msys2とmode_pwshという関数を実行することでリアルタイムに切り替えができるというわけだ。

環境変数の設定や操作を限定的にするところもポイント

MSYS2は、環境変数Pathを適切に設定すれば動作する。ほかにも動作に影響を与える環境変数があるので、日本語環境/日本のタイムゾーンで使うなら、それらの環境変数も適切な値に設定する必要がある。

しかし、この環境変数の設定をWindowsの設定として追加するのは、できれば必要最低限に抑えるのが望ましい。Windowsでも、環境変数はアプリケーションに影響を与えるが、そう頻繁に設定するものではないので、以前に設定した内容を忘れてしまうのはよくあることなのだ。このため、なるべくそう気軽に設定しないほうが無難なのだ。

今回説明したように、PowerShellの$PROFILEで環境変数を設定したり、変更したりするような内容にしておくと、環境変数の影響がPowerShellやそこから起動されるコマンドやアプリケーションに限定される。使いやすく、そして影響も最小限で済むわけだ。こういった点も加味して設定を行うことで、プラットフォームを見通しの良い状態に保つことができる。

付録: MSYS2インストール方法など

環境変数 内容
Path C:\msys64\usr\bin
C:\msys64\mingw64\bin

MSYS2のインストール方法

winget install MSYS2
pacman -Syu
コマンド 内容
pacman -S パッケージインストール
pacman -Ss パッケージ検索
pacman -R パッケージアンインストール
pacman -Rs パッケージおよびそのパッケージのみが必要としているパッケージをアンインストール
pacman -Rns パッケージおよびそのパッケージのみが必要としているパッケージおよびバックアップファイルをアンインストール
pacman -Fx 指定したファイルが含まれているパッケージを一覧表示
pacman -Fl 指定したパッケージがインストールするファイルを一覧表示
pacman -Q インストール済みパッケージ一覧表示
pacman -Syu メタデータアップデートとパッケージアップグレード