何が便利になる? どんな使い方がある?
日本時間の2017年10月18日、Windows 10 Fall Creators Update(バージョン1709)の提供が始まりました。 このバージョンから「Windows Subsystem for Linux(WSL)」が正式な新機能となっていて(※64bit版限定)、これを活用できるようWindowsアプリのストアで「Ubuntu」「openSUSE Leap」「SUSE Linux Enterprise Server」の各Linuxディストリビューションがインストール可能になっています。
これらは「Linux上で動作するプログラムの開発環境」の選択肢の1つとしてももちろん有用ですが、Windows上での一般的な作業の補助ツールとしての有用性にも着目したいところです。
「Windows上でLinuxのコマンドを動かす」という事自体はWSL以前からも既に実現方法がいくつかありますが、Windowsとの親和性を取るか一般的なLinux環境との互換性を取るかのバランスによって、どの選択肢が最適かが変わってきます。以下の表は、大まかな特徴による分類です。
MinGW | Cygwin | WSL | 仮想化(GUIを使用しない場合) | |
---|---|---|---|---|
Windows環境との親和性、Windowsアプリとの連携のしやすさ | ◎ | ◎ | ○ | × |
実行時の速度、メモリ使用効率 | ◎ | ○ | ○ | × |
Linux環境用のプログラムの動作、互換性 | × | △(再ビルドが必要) | ○(サーバーとしての使用は想定外) | ◎ |
この表に示す通り、WSLは既存の取り組みでそれぞれ諦めざるを得なかった部分の両立を図った新しい選択肢と言えます。 端的に言うと、「WindowsにLinux互換のコマンド操作インターフェースが加わった」状態に近いものとなっています。 Linuxのデスクトップ環境やmacOSでは、「普段の操作はGUIで行いつつも、定型的な処理を素早く済ませたい場合には『端末』のウィンドウを開いて、その中で普段サーバーの操作に使っているのと同様のコマンド操作を行う」という使い方ができますが、WSLによってWindowsでもこれに近いことができるようになります。
WSLそのものの導入手順やWSLの仕組みの概要については、技術情報サイトの記事やまんがでわかるWSLなどに譲る事にして、この記事では具体的な活用事例にフォーカスしてご紹介していきます。
なお、Windows 10 Creators Updateおよびそれ以前のバージョンで利用できる「Bash on Ubuntu on Windows」は、現在Windowsのアプリストアから導入可能な「Ubuntu」とは若干構成が異なります。この記事ではWindowsアプリストアからインストールできる「Ubuntu」を対象に説明していきます。
Linux環境からGitリポジトリを操作する
筆者が最も重宝しているのが、Gitのインターフェースとしての利用です。
コミットログを有効に活用するためにはコミットの粒度を適切に分けることが大事ですが、試行錯誤しながらの開発だと、気がつけばあちこちに複数の意図の変更を行った状態になってしまっているということがあります。このような場合、変更を1つ1つのコンテキストごとに少しずつ分割してコミットするのが望ましいですが、GUIでこれをやるのはなかなか手間がかかりますが、git
コマンドではgit add -p
やgit commit -p
を使って、変更をコミットするかどうかを1行単位で簡単に振り分けることができます。
また、仮想環境で完全なLinuxディストリビューションを動作させる以外の方法(例えばGit for Windowsに付属のMinGWによるコマンド操作など)では、今まではLibreOffice Calcのスプレッドシートの変更点をgit diff
で見るような事は簡単にはできませんでした。WSLのUbuntu環境は一般的なUbuntuの環境と非常に近いため、そのような連携も、単に必要なパッケージをapt
でインストールするだけで簡単に実現できます。
Linux環境での処理結果をWindowsのクリップボードにコピーする
WSLでは、Windowsのコンソールアプリケーションやコマンドを、シェルのコマンド列におけるパイプラインの一部に組み込むことができます。これにより、標準入力で与えられた内容を取り扱うWindowsネイティブのコマンドやコンソールアプリをBashのワンライナーの中に自然に組み込むことができます。
中でも特に使い出がありそうなのが標準入力の内容をクリップボードにコピーするclip.exe
で、(コマンド列) | clip.exe
という具合にワンライナーの最後にパイプラインで付け加えるだけで、処理結果をすぐにWindowsアプリケーションに貼り付けることができます。もちろん、それ以外にもnpm
やgem
などでインストールされたコマンドも自由に連携させられます。
WSLを使いやすくする
実際にWSLをLinuxデスクトップのGNOME端末やmacOSのTerminalのように使おうと思うと、気をつけなければならない点や、若干の準備が必要な部分が出てきます。ここでは、筆者が実際に「GitHubでリポジトリを公開している、RubyGemsのパッケージとしてリリースするコマンドラインツールの開発」を行う中で得た知見を元に(具体的にはtiny-classifierの開発時の経験に基づいています)、お薦めの運用の仕方と環境整備手順をご紹介します。
WSLの導入手順そのものの解説は、この記事では省略します。以下の内容はすでにWSLのUbuntuを起動できる状態になっている事を前提としていますので、まだ準備が済んでいないという方はまんがでわかるWSLなどの記事を参考に、先にストアアプリのUbuntuをセットアップしておいて下さい。
Windowsのファイルシステム上のファイルのパーミッションが妥当な形で見えるようにする(2019年4月10日追記)
既定の状態では、/mnt/
以下で見えるWindows側のファイルやフォルダは一律「所有者はroot、グループはroot、パーミッションは書き込み権限があれば777
、無ければ555
」という見え方になり、しかもchmod
やchown
を実行しても何も起こりません。このままだとツールの都合でパーミッションを設定したくてもできませんし、Gitリポジトリを扱うときに無駄に実行権限付きでコミットされてしまって困ります。
WSLでWindowsのファイルシステムをマウントする時の挙動は、/etc/wsl.conf
でカスタマイズできます。以下のように設定しておくと、パーミッション変更がメタ情報として保持されるようになり、また、初期状態ではファイルに実行権限が付かないようになります。
[automount]
options = "metadata,umask=22,fmask=111"
この設定を変更した後は、一端すべてのWSLのコンソールを閉じて、サービス一覧から「LxssManager」を再起動するか、Windows自体を再起動しておきましょう。
よく使うファイルやGitリポジトリにすぐアクセスできるようにする
WSLを起動した時のホームディレクトリは、Windowsのユーザーのホームとは別の場所にあります。逆に、Windowsで普段使用しているファイルにはLinux環境からは/mnt/c/Users/(username)/~
のようなパスで見えます。
よって、Linux環境とWindowsとの間でファイルをやりとりする場合はこのパスでWindowsのフォルダ上のファイルを参照する事になるのですが、このように深いパスを何度も書くのは非効率的です。
この問題の解決の方向としては、以下の3パターンが考えられます。
-
Linux環境のディレクトリの実体へのショートカットをWindows側に作成し、Windowsから見に行く。
-
Windows側のフォルダへのシンボリックリンクをLinux環境内に作成し、Linux環境から見に行く。
この中で最も安全でお薦めしやすいのは、3番目の「Windows側のフォルダへのシンボリックリンクをLinux環境内に作成する」方法です。
まず1番目の「WindowsのユーザーのホームをLinux環境のホームディレクトリにする」という方法ですが、これはお薦めできません。何故かというと、まず先述したとおり、初期状態のWSLではマウントしたWindowsのファイルの所有者やパーミッションがおかしなことになります。この問題は/etc/wsl.conf
の設定で回避できるのですが、他にも、大文字小文字が異なるだけの名前のファイルを作成しようとしてもWindows側ではそれらが同一視されてしまうという問題があります。そういったWSL固有の問題について、自分で開発するプログラムにおいては気をつける事もできますが、パッケージなどで導入した一般的なツールがそのような特殊な事情を考慮してくれていると期待するのはハイリスクです。
2番目の「Linux環境からはWindowsのファイルに触らないことにして、Linux環境のホームディレクトリの実体へのショートカットを作成してWindows側からファイルを操作するようにする」という方法も、安全ではないためお薦めできません。WSLのUbuntu環境のホームは%AppDataLocal%\Packages\CanonicalGroupLimited.UbuntuonWindows_(ランダムな文字列)\LocalState\rootfs\home\(username)
という位置に実体となるフォルダが存在していますが、この実体配下のフォルダやファイルを不用意にWindows側から触ると、Linux環境からファイルが見えなくなったり、Linux環境から見た時の内容とWindowsから見た時の内容が異なるファイルになったり、果ては削除不可能なフォルダやディレクトリができてしまったりと、様々な不可解な事態が発生して収拾が付かなくなってしまいます。この実体フォルダ配下にはWindowsからは絶対に触らないようにしましょう。
このように、1番目と2番目の方法は全くそれと意識しない通常の操作を行っていても環境が破壊されてしまうリスクが高いのですが、Windows側のフォルダ配下にあるファイルを意図的に読み取ったり書き込んだりする限りにおいては、そのようなトラブルは起こりません。 ですので、
-
参照する機会が多いWindowsのファイルやフォルダがある場合は、シンボリックリンクをLinux環境のホーム以下に作成しておく。
-
例えば、
C:\Users\(username)\Downloads
に保存したファイルをBashから参照する機会が多いならln -s /mnt/c/Users/(username)/Downloads ~/Downloads
、デスクトップ上にあるファイルを参照する機会が多いならln -s /mnt/c/Users/(username)/Desktop ~/Desktop
、マイドキュメントならln -s /mnt/c/Users/(username)/Documents ~/Documents
といった具合でシンボリックリンクを用意しておく。 -
コマンドの実行時には、これらのシンボリックリンクを
cat ~/Desktop/list.csv | cut -f 2 | sort | uniq -n > ~/Desktop/result.txt
のように参照する。
-
-
Windowsのファイルやフォルダが意図せず実行権限付きでコミットされてしまわないよう、あらかじめgit config --global core.filemode false
として、ファイルの実行権限の変化をGitで検知しないようにしておく。-
これをしないまま、Linux環境のホーム以下でgit clone
して作業中だったGitリポジトリをmv repo /mnt/c/Users/Public/
などとしてWindows側のフォルダ配下に移動すると、前述した現象により全てのファイルのパーミッションが777
に変更されたことになり、全ファイルに実行権限を付与するコミットが行われてしまう危険性がある。 -
ファイルの実行権限を明示的にリポジトリに保存したい場面では、TortoiseGitなどのGUIから操作するか、git update-index --add --chmod=+x path/to/file
(実行権限を与える)およびgit update-index --add --chmod=-x path/to/file
(実行権限をなくす)を使う。
-
-
Windowsのフォルダ配下では、ファイル名の大文字小文字の違いやファイルのパーミッションが重要な意味を持つ操作は行わない。
-
例えばGemやnpmのパッケージのリリース操作を行うと、内容物のパーミッションがすべて
777
になったパッケージができてしまう。このようなパッケージをsudo gem install
やsudo npm install
でインストールされると、管理者権限がないユーザーが自由に書き換えられる状態のファイルがインストールされてしまうため、セキュリティリスクとなる。 -
パーミッションが意味を持つ操作を行う時は、必ずLinux環境のホーム以下に移動してから実行する。Gemやnpmのパッケージのリリース操作であれば、リリース操作用として、Linux環境のホーム以下にもGitリポジトリをcloneしておく。
-
とするのが、Linux環境とWindowsの間で共通のファイルやGitリポジトリを操作するときのお薦めの運用と言えます。
実際に、筆者はC:\Users\Public
以下に(TortoiseGitでcloneした物も含めて)Gitリポジトリを置き、Windowsのテキストエディタで編集した結果をLinux環境からgit commit -p
などとしてコミットするという使い方をしています。Linux環境上でのパーミッションの表示が常に777
になってしまう(chmod
でのパーミッション変更ができない)ということと、それ故この位置に置いたリポジトリからはパッケージをリリースできないという点を除けば、概ね支障なく運用できています。
SSHエージェントを使い、秘密鍵のパスフレーズ入力を省略する
2020年2月7日追記:Windows 10 1803以降のバージョンでは、Windowsに最初からサービスとして登録されているOpenSSH Authentication Agentとrupor-github/wsl-ssh-agentを使う方法が利用でき、そちらの方がおすすめです。以下は歴史的資料として参照するに留めてください。
BitbucketやGitHubなどのリポジトリ共有サービスでは、パスワード認証よりも安全な認証方式として、SSHの公開鍵を使った鍵認証を選択できるようになっています。秘密鍵を使うにはパスフレーズの入力が必要ですが、LinuxデスクトップではGNOME KeyringなどのSSHエージェントが、macOSではKeychainという同様の仕組みが導入されているため、ユーザーはいちいちパスフレーズを入力しなくても良いようになっています。大抵はセッション開始時の1回だけパスフレーズを入力してやれば、あとは鍵認証の処理をSSHエージェントが代行してくれるというわけです。
WSLでも当然、GitからのSSH接続で公開鍵認証を使えますが、実際には使い勝手は良くありません。何故かというと、WindowsにはGNOME KeyringやKeychainのような標準的な仕組みが無いからです。そのため、git push
やgit pull
の度に毎回パスフレーズの入力を求められることになります。
この問題の最も簡単な解決方法は、SSHエージェントを使うというものです。具体的には、~/.bashrc
に以下の内容を記載しておくと、Windowsを起動してから最初にWSLのUbuntuを起動したときに1回だけパスフレーズを入力すれば、以後Windowsを終了するまでの間は再度のパスフレーズ入力を求められなくなります(解説)。
SSH_AGENT_FILE=$HOME/.ssh-agent
test -f $SSH_AGENT_FILE && source $SSH_AGENT_FILE
if ! ssh-add -l > /dev/null 2>&1; then
ssh-agent > $SSH_AGENT_FILE
source $SSH_AGENT_FILE
ssh-add $HOME/.ssh/id_rsa # この位置にOpenSSHの秘密鍵があると仮定
fi
Pageantとの連携
ただ、ssh-agent
を使う方法には「実際に秘密鍵を使うかどうかに関わらず、WSLのUbuntuを起動すると(最初の1回は)必ず秘密鍵のパスフレーズの入力を求められる」という欠点があります。単にローカルのテキストファイルをシェルスクリプトで加工するためだけにWSLを起動したというような場面でもパスフレーズの入力を求められるので、急いでいるようなときには不便でしょう。
これに代わる筆者のおすすめは、Pageantとweasel-pageantを組み合わせるという運用です。
Pageantは「PuTTY」というWindows用のSSHクライアント用のSSHエージェントですが、TortoiseGitなどにも同梱されており、Windows用のSSHエージェントの代表的な物と言えます。ただし、これ単体で使用するとWSLのUbuntu上のssh-agent
とは別に動作することになりますので、それぞれで個別に秘密鍵をロードしなくてはなりません。
ssh-agent
の代わりにweasel-pageantを使うと、Linux環境からPageantに読み込まれた秘密鍵を使って公開鍵認証を行えるようになります。Windows上でパスフレーズを入力して秘密鍵を読み込ませておけば、Linux環境で改めてパスフレーズを入力する必要はありません。Windows上でPageantと連携して公開鍵認証を行うTortoiseGitなどのアプリを併用するのにも好都合です。
手順としては、まずPageantを導入します。全く初めての利用であれば、PuTTYのインストーラをダウンロードしてインストールすると、インストールされたファイル一式の中にpageant.exe
という名前でPageantが含まれています。TortoiseGitを導入済みの場合は、TortoiseGitのインストール先のbin
フォルダ内にすでにPageantが存在しています。このpageant.exe
へのショートカットをスタートアップに登録して、Windowsログイン時に自動起動するようにして下さい。
(なお、この時Pageantのショートカットのプロパティで「リンク先」欄のpageant.exe
へのパスの後に半角スペースを空けて秘密鍵のフルパスを指定すると、Windowsログオン時に自動的にその鍵を読み込んでパスフレーズの入力を求めてくるようになります。)
次に、weasel-pageantをインストールします。weasel-pageantのリリースページから最新のweasel-pageant-*.zip
をダウンロードして、このファイルの内容をC:\Program Files (x86)\weasel-pageant
に展開しましょう。weasel-pageantはWindowsアプリなので、ファイルは必ずWindows側の領域に置いて下さい。Linux環境内に置くと動作しないので注意が必要です。
そして、WSLのUbuntuの起動時に毎回weasel-pageantを自動実行するよう、~/.bashrc
に以下のような行を追加します(weasel-pageantの設置先パスは実際の位置に合わせて下さい)。
eval $(/mnt/c/Program\ Files\ \(x86\)/weasel-pageant/weasel-pageant -r)
以上で準備は完了です。スタートアップに登録したアプリケーションが起動されるように、一旦ログアウトして再度ログインしましょう。タスクトレイにPageantのアイコンが表示されるようになっているはずです。
これをダブルクリックして鍵一覧を表示し、「Add」ボタンをクリックして秘密鍵(※Linux等でOpenSSHの秘密鍵を使っていた場合は、puttygen.exe
を使ってPuTTY形式の秘密鍵に変換しておく必要があります)を選択します。パスフレーズを入力して秘密鍵をPageantに読み込ませたら、以後Pageantが終了するまでの間はずっと、Linux環境上での鍵認証にはPageantが使われるようになります。
試しに、WSLを起動して、git clone git@github.com:(username)/(project-name).git
のように鍵認証を伴う操作を行ってみましょう。パスフレーズの入力を求められずに処理が進行することを確認できるはずです。
過剰な権限があるディレクトリの存在に起因するRubyの警告を抑止する
WSL上でGemによってインストールされたコマンドを実行すると、warning: Insecure world writable dir /mnt/c in PATH, mode 040777
のような警告のメッセージが表示されるようになる場合があります。最も単純な例では、ruby -e 'system("true")'
というコマンド列を実行するだけでもこの現象の発生を確認できます。
この現象は、前述の「Windows側のファイルが所有者root、アクセス権777に見える」という問題に起因しています。WSLではWindowsの実行ファイル(「メモ帳」など)を直接起動しやすいように、Bash起動時の環境変数PATH
にWindowsの環境変数PATH
の内容がインポートされるようになっています(cat file.txt | clip.exe
のような操作を行えるのはこのお陰です)。しかし、これによってコマンドの探索対象に加わる/mnt/c/Windows
などのディレクトリのパーミッションがLinux環境では777
と見えるために、Rubyスクリプト内でシェルコマンドを探すためにPATH
を走査した時に、Rubyが気を利かせて上記の警告を表示してしまうというわけです。
このPATH
の自動インポート機能は他にも様々な部分に影響を及ぼすということで、WSLの公開のIssue Tracker上でも取り上げられています。対策としては、以下のような方法が考えられます。
-
環境変数
PATH
にWindowsのパスを含めないようにする。 例えば~/.bashrc
の冒頭にexport PATH="$(echo "$PATH" | sed -r -e 's;:/mnt/[^:]+;;g')"
と追記しておけば、Windowsの環境変数からインポートされたパスが取り除かれた状態になります。この結果、clip.exe
のようなWindowsのコマンドをフルパスを指定しなければ実行できなくなるというデメリットがあります。Windowsのコマンドとの連携を考えないのであれば、この方法がお薦めです。 (レジストリを編集する方法もありますが、筆者環境での検証時には、WindowsアプリストアのUbuntuでは設定が反映されませんでした。) -
Rubyの既定の起動オプションを指定する環境変数
RUBYOPT
で、-W0
を指定しておく。-W0
はそのものずばり警告を表示しないようにするという指定です(既定値は-W1
で、重要な警告のみ表示されます)。例えば~/.bashrc
の末尾にexport RUBYOPT=-W0
と追記しておけば、上記の物も含めて煩わしい警告が全て表示されなくなります。ただ、それらの中にはデバッグのために有用な情報が含まれる場合がありますので、それらが得られなくなってデバッグしにくくなるというデメリットがあります。Windowsのコマンドとの連携を積極的に活用したいのであれば、この方法がお薦めです。
コンソールの文字色を見やすくする
これまでWindowsのコマンドプロンプトやその他のコンソールアプリで使われてきた配色には、液晶ディスプレイにおいては色の判別が難しいという問題がありました。PC使用環境の変化を受けてWindows 10 Fall Creators Updateではより見やすい配色への変更が行われています。
しかしながら、この新しい配色は新規インストールの環境にのみ反映され、従来バージョンからWindows 10 Fall Creators Updateに更新した環境では以前のままの配色が使われます。これでは文字が見にくい状態のままとなりますので、文字色をより明るい色に変更しておく事をお薦めします。Cortanaで「regedit」と入力してレジストリエディタを起動し、キーHKEY_CURRENT_USER\Console
を選択すると、dword型のColorTable00
からColorTable15
までの16個の値が並んでいます。これらがWindowsのコンソールアプリで使われる共通のカラーパレットになっていますので、以下の通り値の内容を変更します。
-
ColorTable01
(暗い青):00800000
(10進数のRGB表記のR0/G0/B128に対応)を00ff4221
(R33/G66/B255)へ変更。 -
ColorTable09
(明るい青):00ff0000
(R0/G0/B255)を00ff8021
(R33/G128/B255)へ変更。
以上で色の変更は完了です。以後は、WSLだけでなくcmd.exe
を起動した場合なども含めて、全てのコンソールアプリの青が明るい青で表示されるようになります。
他にも見にくい色がある場合や、上記の設定でもまだ暗くて見にくい場合には、色のカスタマイズの例を参考にして、好みで明るめの配色に調整すると良いでしょう。
まとめ
以上、WSLを日常的に使うにあたって躓きやすい部分を中心として、お薦めの設定と運用方法の例をご紹介してみました。
Windowsは不自由な部分もありますが、プリインストールPCの選択肢が豊富だったり、商用の高性能・高機能なアプリケーションやゲームが充実していたり、ハードウェアの最新のドライバが手に入りやすかったりと、純粋な道具としてPCを使いたい需要に対しては依然として有力な選択肢です。それらのメリットを享受した上で、Linux環境のツールとしての自由度の高さを同時に得られる物として、WSLにはおおいに利用価値があります。皆さんもぜひこの機会に、「Windows上のLinux環境」を試してみて下さい。