Windows 11ではWindows Terminalがデフォルトのターミナルアプリケーションとなり、PowerShell 7がデフォルトのシェルになる。当然、MSYS2はこの環境で使うというのがデフォルト状態になるはずだ。しかし、MSYS2コマンドのいくつかはPowerShellと衝突するため、使い勝手の悪いところがある。今回はこの部分を調整する方法を取り上げる。

PowerShellのエイリアス

WindowsのシェルであるPowerShellはオブジェクト指向のプログラミング言語だ。シンタックスがLinuxで使われるシェルに似せてあるため、一見するとUNIX系のシェルのように使えるが、かなりゴリゴリのプログラミング言語であり、管理や操作という面では強力この上ない。

このPowerShellには「エイリアス」という別名の機能があり、コマンドやコマンドレット、関数などに別の名前を与えることができるようになっている。デフォルトで割り振られているエイリアス名のいくつかがLinux系コマンドの名前と同じになっているため、MSYS2やWSLがセットアップされていない状態でも、あたかもLinuxコマンドのように使うことができている。

例えば、以下の表はPowerShellエイリアスで特によく使われるLinuxコマンド名と、同じ名前が使われているものをまとめたものだ。実際には同名のコマンドではなく、PowerShellのコマンドレットが実行される。

PowerShellエイリアス 対応するコマンドレット
cat Get-Content
cp Copy-Item
diff Compare-Object
echo Write-Output
ls Get-ChildItem
mv Move-Item
rm Remove-Item
sort Sort-Object
tee Tee-Object

MSYS2がインストールされていないときには便利な機能なのだが、MSYS2がインストールされた後は勝手が異なる。エイリアスのほうが優先的に解釈されるので、MSYS2のコマンドではなくPowerShellのコマンドレットが実行されるのだ。MSYS2をインストールするということは、Linuxコマンドを使いたいからなのに、PowerShellエイリアスのほうが優先して使われるのは困ってしまう。

PowerShellのエイリアスがMSYS2コマンドとか被る問題

例えば、「ls」は「Get-ChildItem」というコマンドレットへのエイリアスになっている。「dir」も実体は「Get-ChildItem」だ。

PS C:\Users\daichi> alias | grep ls
Alias           cls -> Clear-Host
Alias           ls -> Get-ChildItem
Alias           sls -> Select-String
PS C:\Users\daichi> alias | grep dir
Alias           chdir -> Set-Location
Alias           dir -> Get-ChildItem
Alias           md -> mkdir
Alias           rmdir -> Remove-Item
PS C:\Users\daichi> Get-Command ls

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           ls -> Get-ChildItem

PS C:\Users\daichi> Get-Command Get-ChildItem

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Get-ChildItem                                      7.0.0.0    Microsoft.PowerShell.Management

PS C:\Users\daichi>

したがって、lsの結果も、dirの結果も次のように同じになる。

PS C:\Users\daichi\Documents> ls

    Directory: C:\Users\daichi\Documents

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2021/07/19    19:32                chrome-ext
d----          2021/08/15    18:53                config
da---          2021/07/31    15:06                ISOs
d----          2021/08/16     7:58                keyboard-shortcuts
d----          2021/08/15    18:46                lwt
d----          2021/09/12    15:23                misc
d----          2021/08/31    16:40                misc-old
d----          2021/08/29    10:57                mynavi
d----          2021/08/02    11:09                postal-code-data
d----          2021/07/20     8:26                powershell
d----          2021/09/12    19:03                setup
d----          2021/09/12    19:24                tttcmds
d----          2021/09/12    13:39                tttcmds-old
d----          2021/08/14    15:02                vscode-csv2tsv
d----          2021/09/04     9:39                word-of-mouth

PS C:\Users\daichi\Documents> dir

    Directory: C:\Users\daichi\Documents

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2021/07/19    19:32                chrome-ext
d----          2021/08/15    18:53                config
da---          2021/07/31    15:06                ISOs
d----          2021/08/16     7:58                keyboard-shortcuts
d----          2021/08/15    18:46                lwt
d----          2021/09/12    15:23                misc
d----          2021/08/31    16:40                misc-old
d----          2021/08/29    10:57                mynavi
d----          2021/08/02    11:09                postal-code-data
d----          2021/07/20     8:26                powershell
d----          2021/09/12    19:03                setup
d----          2021/09/12    19:24                tttcmds
d----          2021/09/12    13:39                tttcmds-old
d----          2021/08/14    15:02                vscode-csv2tsv
d----          2021/09/04     9:39                word-of-mouth

PS C:\Users\daichi\Documents>

MSYS2をインストールしたら、lsで「C:\msys64\usr\bin\ls.exe」が実行されてほしい。そうなれば、Linuxで使っているときと同じような出力が得られる。

PS C:\Users\daichi\Documents> C:\msys64\usr\bin\ls.exe
 ISOs          'My Videos'   desktop.ini          misc       postal-code-data   tttcmds          word-of-mouth
'My Music'      chrome-ext   keyboard-shortcuts   misc-old   powershell         tttcmds-old
'My Pictures'   config       lwt                  mynavi     setup              vscode-csv2tsv
PS C:\Users\daichi\Documents> C:\msys64\usr\bin\ls.exe -l
total 421
drwxr-xr-x 1 daichi daichi   0 Jul 31 15:06  ISOs
lrwxrwxrwx 1 daichi daichi  21 Jun 10 19:22 'My Music' -> /c/Users/daichi/Music
lrwxrwxrwx 1 daichi daichi  24 Jun 10 19:22 'My Pictures' -> /c/Users/daichi/Pictures
lrwxrwxrwx 1 daichi daichi  22 Jun 10 19:22 'My Videos' -> /c/Users/daichi/Videos
drwxr-xr-x 1 daichi daichi   0 Jul 19 19:32  chrome-ext
drwxr-xr-x 1 daichi daichi   0 Aug 15 18:53  config
-rw-r--r-- 1 daichi daichi 418 Jul 19 20:46  desktop.ini
drwxr-xr-x 1 daichi daichi   0 Aug 16 07:58  keyboard-shortcuts
drwxr-xr-x 1 daichi daichi   0 Aug 15 18:46  lwt
drwxr-xr-x 1 daichi daichi   0 Sep 12 15:23  misc
drwxr-xr-x 1 daichi daichi   0 Aug 31 16:40  misc-old
drwxr-xr-x 1 daichi daichi   0 Aug 29 10:57  mynavi
drwxr-xr-x 1 daichi daichi   0 Aug  2 11:09  postal-code-data
drwxr-xr-x 1 daichi daichi   0 Jul 20 08:26  powershell
drwxr-xr-x 1 daichi daichi   0 Sep 12 19:03  setup
drwxr-xr-x 1 daichi daichi   0 Sep 12 19:24  tttcmds
drwxr-xr-x 1 daichi daichi   0 Sep 12 13:39  tttcmds-old
drwxr-xr-x 1 daichi daichi   0 Aug 14 15:02  vscode-csv2tsv
drwxr-xr-x 1 daichi daichi   0 Sep  4 09:39  word-of-mouth
PS C:\Users\daichi\Documents>

では、どうやって実現すればよいのかという話だが、PowerShellのエイリアスを削除して、新しくMSYS2のコマンドへエイリアスを張ればよいのだ。まず、次のようにコマンドを実行することで、エイリアスの削除を行える(ここではcat、cp、ls、mv、rmのエイリアスを削除している)。

# 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

そして、新しくMSYS2コマンドへエイリアスを設定する。

# MSYS2コマンドへのエイリアスを作成
Set-Alias -Name cat -Value C:\msys64\usr\bin\cat.exe
Set-Alias -Name cp -Value C:\msys64\usr\bin\cp.exe
Set-Alias -Name mv -Value C:\msys64\usr\bin\mv.exe
Set-Alias -Name rm -Value C:\msys64\usr\bin\rm.exe

PowerShellのエイリアスは、本当に別名をつけるだけの機能だ。Linuxのシェルであれば、エイリアスはただの文字列の置き換えであることが多いため、エイリアスにオプションなどコマンド以外の要素を含めることができるのだが、PowerShellではそれができない。

そういった場合にはエイリアスではなく関数を定義すればよい。例えば、次のように関数を用意すれば、lsで「C:\msys64\usr\bin\ls.exe —color $Args」が実行されるようになり、「ll」で「C:\msys64\usr\bin\ls.exe —color $Args -l」が実行されるようになる。

# ls系はオプションを指定するために関数で定義
function ls { C:\msys64\usr\bin\ls.exe --color $Args }
function ll { C:\msys64\usr\bin\ls.exe --color $Args -l }
function la { C:\msys64\usr\bin\ls.exe --color $Args -a }

WindowsのシステムコマンドがMSYS2コマンドと被る問題

PowerShellではWindowsのシステムコマンドも使われている。システムコマンドのなかにはLinuxコマンドと同じ名前のものがある。例えば、Linuxには「find」があるが、Windowsでは「C:\WINDOWS\system32\find.exe」が用意されている。同じ名前だが、別の目的のコマンドだ。

PS C:\Users\daichi\Documents> Get-Command find | Format-List

Name            : find.exe
CommandType     : Application
Definition      : C:\WINDOWS\system32\find.exe
Extension       : .exe
Path            : C:\WINDOWS\system32\find.exe
FileVersionInfo : File:             C:\WINDOWS\system32\find.exe
                  InternalName:     find
                  OriginalFilename: FIND.EXE.MUI
                  FileVersion:      10.0.19041.1165 (WinBuild.160101.0800)
                  FileDescription:  文字列検索 (grep) ユーティリティ
                  Product:          Microsoft® Windows® Operating System
                  ProductVersion:   10.0.19041.1165
                  Debug:            False
                  Patched:          False
                  PreRelease:       False
                  PrivateBuild:     False
                  SpecialBuild:     False
                  Language:         日本語 (日本)



PS C:\Users\daichi\Documents>

「tree」も同様に、Windowsには「tree.com」というコマンドがある。

PS C:\Users\daichi\Documents> Get-Command tree | Format-List

Name        : tree
CommandType : Function
Definition  :  tree.com /f


PS C:\Users\daichi\Documents>

この2つのコマンドはよく似ている。Windowsではtree.comのほうがよほど動作が高速だ。ただ、機能はLinux treeのほうが多い。ユーティリティ的に使うなら、Linuxのほうを使いたい。

こうしたシステムコマンドに関しては、エイリアスを設定して済むならそうするのが簡単である。エイリアスのほうが優先的に実行されるからだ。PowerShellでは、次のように実行すればエイリアスを設定することができる。

# WindowsコマンドをMSYS2コマンドで置き換え
Set-Alias -Name find -Value C:\msys64\usr\bin\find.exe
Set-Alias -Name tree -Value C:\msys64\usr\bin\tree.exe

削除できないPowerShellエイリアスはどうすればよいか

全てがこの方法でうまくいくかと言えばそんなことはなく、いくつかのエイリアスは削除できないようになっている。次のように「diff」「sort」「tee」はそのままでは削除できないのだ。

PS C:\Users\daichi> Remove-Alias diff
Remove-Alias: Alias was not removed because alias diff is constant or read-only.
PS C:\Users\daichi> Remove-Alias sort
Remove-Alias: Alias was not removed because alias sort is constant or read-only.
PS C:\Users\daichi> Remove-Alias tee
Remove-Alias: Alias was not removed because alias tee is constant or read-only.
PS C:\Users\daichi>

無理やり削除することも可能だが、わざわざ削除できない設定になっているので、削除しないほうが無難だ。こんなときは、次のように異なる名前で関数を作成しておこう。何もしないよりもよほど使いやすくなる。

# 削除できないエイリアスについては別名を付与
function msys2_diff { C:\msys64\usr\bin\diff.exe $Args }
function msys2_sort { C:\msys64\usr\bin\sort.exe $Args }
function msys2_tee { C:\msys64\usr\bin\tee.exe $Args }

設定を$PROFILEへ書き込んでおく

後は、ここまでに取り上げた設定を「$PROFILE」に書き込んでおけばPowerShellの起動に適用される。$PROFILEのパスは環境によって異なるのだが、「Microsoft.PowerShell_profile.ps1」という名前のファイルになっているはずだ。ターミナルで「notepad $PROFILE」を実行して編集を行ってしまうのが簡単だろう。次のような内容を追加しておけばよい。

if (Test-Path -PathType Container C:\msys64\) {
        # 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

        # MSYS2コマンドへのエイリアスを作成
        Set-Alias -Name cat -Value C:\msys64\usr\bin\cat.exe
        Set-Alias -Name cp -Value C:\msys64\usr\bin\cp.exe
        Set-Alias -Name mv -Value C:\msys64\usr\bin\mv.exe
        Set-Alias -Name rm -Value C:\msys64\usr\bin\rm.exe

        # ls系はオプションを指定するために関数で定義
        function ls { C:\msys64\usr\bin\ls.exe --color $Args }
        function ll { C:\msys64\usr\bin\ls.exe --color $Args -l }
        function la { C:\msys64\usr\bin\ls.exe --color $Args -a }

        # WindowsコマンドをMSYS2コマンドで置き換え
        Set-Alias -Name find -Value C:\msys64\usr\bin\find.exe
        Set-Alias -Name tree -Value C:\msys64\usr\bin\tree.exe

        # 削除できないエイリアスについては別名を付与
        function msys2_diff { C:\msys64\usr\bin\diff.exe $Args }
        function msys2_sort { C:\msys64\usr\bin\sort.exe $Args }
        function msys2_tee { C:\msys64\usr\bin\tee.exe $Args }
}

この設定を追加するだけで、MSYS2をインストールした後のPowerShellプロンプトをある程度Linux環境のように使うことができるようになる。

本連載はPowerShellが主テーマではないので、PowerShellに関する説明はここで止めておく。興味がある場合には別連載「PowerShell Core入門 - 基本コマンドの使い方」などを参考にしてもらえれば幸いだ。

いずれにせよ、Linuxを使う上でもWindowsは避けて通ることが難しいプラットフォームである。であれば、なるべくLinuxユーザーが扱いやすいようにカスタマイズしたり、操作の中心となるシェルについて知っておいたりすることは悪くない。PowerShell 7はLinuxでも使えるし、興味があるならPowerShellの活用にも取り組んでみると良いと思う。このパワフルなシェルは、Linuxで使う上でも新しいアイデアを与えてくれるはずだ。

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

環境変数 内容
HOME C:\Users\ユーザ名
LC_CTYPE ja_JP.UTF-8
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 メタデータアップデートとパッケージアップグレード