Terminal
fish
WSL
hyper

Windows で WSL + Hyper + fish shell 環境を再構築する

More than 1 year has passed since last update.


WSL

WSL ( Windows Subsystem for Linux ) は、Windows 上で動作できる Linux ( Unix ) っぽい環境の一つ。

有名どころでは Cygwin や MSYS2 などと競合するが、


  • Microsoft が公式に提供している

  • Linux Distributions 環境をほぼそのまま使える

  • Windows 10 を利用しているユーザであれば、比較的簡単に入れられる

などは強みだ。最近ベータも外れたので、本格導入に向けて再調査した。

https://docs.microsoft.com/en-us/windows/wsl/about


インストール

Install your Linux Distribution of Choice


WSL の有効化

まずは、有効にするために管理者権限で起動した Powershell で以下を実行する。

PS> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

その後再起動すると、WSL が使えるようになる。


アプリストアから Linux Distribution をインストール

古いバージョンが入っている場合は、最新版をストアから取得する。


● WSL のバージョン確認

古いバージョンは、こんな感じに Legacy と出る。

before.jpg

もう使わないので、先にアンインストールした。


● 最新 WSL のインストール ( Ubuntu の場合 )

インストールが完了したら、Ubuntu が規定になっていることを確認する。

after.jpg

Ubuntu 以外にも、様々な Linux Distribution が提供されている。


  • Debian

  • SUSE Linux

  • OpenSUSE

  • Kali Linux

特にこだわりが無いなら、Ubuntu が最も情報が多く、安心。


個人的必須パッケージのインストール

自分が使う上で最低限必要なパッケージを入れておく。

$ sudo apt-get update

$ sudo apt-get upgrade
$ sudo apt-get install curl jq git tig openssl ca-certificates build-essential software-properties-common iproute2

# fzf
$ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
$ ~/.fzf/install

# micro
$ cd /usr/local/bin
$ curl https://getmic.ro | sudo bash

# exa
$ curl -LO https://github.com/ogham/exa/releases/download/v0.8.0/exa-linux-x86_64-0.8.0.zip
$ unzip exa-linux-x86_64-0.8.0.zip
$ sudo chown root:root exa-linux-x86_64 && mv exa-linux-x86_64 /usr/bin/exa

# ripgrep
$ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.8.1/ripgrep_0.8.1_amd64.deb
$ sudo dpkg -i ripgrep_0.8.1_amd64.deb && rm ripgrep_0.8.1_amd64.deb

# bat
$ curl -LO https://github.com/sharkdp/bat/releases/download/v0.4.1/bat_0.4.1_amd64.deb
$ sudo dpkg -i bat_0.4.1_amd64.deb && rm bat_0.4.1_amd64.deb


相互運用性

Fall Creators Update や Anniversary Update を経て、Windows と Linux ( WSL ) の相互運用性は大きく高まっていた。

WSL interoperability with Windows | Microsoft Docs

Bash on Windows と呼ばれていた時代は文字通り bash.exe で起動していたが、これは現在 Deprecated となっている。

今後は wsl.exe で起動 する。

bash.exe 時代からの違いとしては、以下がある。



  • -c が要らなくなった

  • Windows の %Path%$Path に取り込める (あれ、この機能って昔から無かったっけ??)


◆ Windows Platform から Linux Platform を利用する場合

Windows 側から Linux コマンドを動かしたい場合、以下のように実行できる。

PS> ipconfig | wsl grep IPv4   # この grep は、Linux 上の grep

IPv4 Address. . . . . . . . . . . .: 172.10.20.30
IPv4 Address. . . . . . . . . . . .: 10.0.100.200

wsl を頭につけるだけ で呼び出せる。とても楽だし、可読性も損ねてはいない。


● Windows 向けバイナリとの比較

これまで自分は、scoop を使って Windows 用にコンパイルされた Linux コマンドを山程入れていた

しかし、それらは大抵 起動がワンテンポ遅く、また一部のコマンドにおいてはバージョンも古かったり、動作やコマンド体系・オプションが Linux 版と全然違ったり と、満足行くものではなかった。

それに比べて今の WSL は、簡単で、軽量で、かつ シームレスに動作 できるものが 公式 に提供されている。

乗り換えない理由は無かった。


● Alias 追加

ということで、早速 wsl <<Linux コマンド>> を Alias として登録し、よりシームレスに統合する。

Powershell で Alias を登録する場合、Powershell の Profile である Powershell_profile.ps1 に追加することで可能となる。

自分は別ファイルに切り出しモジュール化し、それをプロファイルで Import-Module するようにしている。


Wsl.ps1

function wsl_grep() {

$input | wsl grep $args
}

Set-Alias -Name:"grep" -Value:"wsl_grep" -Option:Allscope



Powershell_profile.ps1

Import-Module "C:\path\to\Wsl.ps1"


これで、ほぼシームレスな連携が可能となる。

PS> ipconfig | grep IPv4

IPv4 Address. . . . . . . . . . . .: 172.10.20.30
IPv4 Address. . . . . . . . . . . .: 10.0.100.200

自分用に使いそうなコマンドの Alias・Functions をまとめた Powershell ファイルを作ったので、参考に。

https://gist.github.com/kentork/bd85a670302a22852b55652afe59ef47

mkdir のように Windows でも同名のコマンドが存在する場合は、Windows アプリケーションに意図しない影響を与える事もあるので注意。


◆ Linux Platform から Windows Platform を利用する場合

今度は、WSL の中から Windows コマンドを利用する場合を考える。

実は、これも簡単にできる。

$ ipconfig.exe | grep IPv4   # この ipconfig は、Windows 上の exe

IPv4 Address. . . . . . . . . . . : 172.10.20.30
IPv4 Address. . . . . . . . . . . : 10.0.100.200

ポイントとしては、Windows のバイナリを動かすときは ~.exe までしっかり入力 すること。

また、dir /b などの / で指定するオプションは、 dir -b のように /- に変更する必要があるようだ。


◆ どっちがメイン?

CLI 周りのエコシステムを考えると、どうしたって Linux に軍配が上がってしまう。

今は Linux Platform から Windows Platform を利用する 方を基軸としている。

とは言え、まだまだ Powershell を使いたいケースはあるので、Windows Platform から Linux Platform を利用する方法も残している。


パス表現の違い

WSL を運用する上で無視できないのが、この パス表現の違い

image.png

見るだけであれば、慣れてくれば頭の中で変換できるようになってくるが、


  • Case 1. wsl rm -r hoge/piyo.jsonpiyo.json を Tab 補完で見つけようとすると Windows スタイルになってエラー

  • Case 2. wsl find -type f > files.txt で出力されるファイル一覧が Linux スタイルに

などのケースがよく起こる。地味に辛い。Alias 使ってて意識が向きづらくなると特にハマりやすい。

● Windows 側での対応

一応、変換するための関数を Powershell で自作している。


Wsl.ps1

function w2l($in) {

if ( $in -match "(^[a-zA-Z]:(\\{1,2})?$|^[a-zA-Z]:\\{1,2}[^\\])") {
$in = "/mnt/" + $in.Substring(0, 1).ToLower() + $in.Substring(2).Replace('\\', '/').Replace('\', '/')
} elseif ( $in -match "(^\.(\\{1,2})?$|^\.\\{1,2}[^\\])") {
$in = $in.Replace('\\', '/').Replace('\', '/')
}
return $in
}
function l2w($in) {
if ( $in -match "(^/mnt/[a-z]/?|^/mnt/[a-z]/[^/])") {
$in = $in.Substring(5, 1).ToUpper() + $in.Substring(6).Replace('/', '\')
} elseif ( $in -match "(^\./?$|^\./[^/])") {
$in = $in.Replace('/', '\')
}
return $in
}
function w2ls() { $input | %{ w2l($_) } }
function l2ws() { $input | %{ l2w($_) } }

PS> wsl rm -r $(w2l .\hoge)

PS> wsl find -type f | l2ws > files.txt

正直、エラーになって初めて気がつき、それから対策として使うケースが多い。

それでもやっていけないわけではないが、根本的な解決策は欲しい。

● Linux 側での対応

2018 年 3 月のアップデートから、Linux 側に wslpath というコマンドが追加され、Linux style ⇔ Windows style ができるようになった。

せっかく公式にあるので、Linux 側ではそれを利用している。

( 以下、fish を前提にしている為、他の Shell の場合は読み替えて )


config.fish

alias w2l='wslpath'

alias l2w='wslpath -w'
function w2ls
while read -l line
wslpath $line
end
end
function l2ws
while read -l line
wslpath -w $line
end
end

$ find -type f | l2ws > files.txt

● 環境変数の相互変換

wsl.exe になり、 WSL → Windows または Windows → WSL で環境変数が継承されるようになったが、その場合にパス表現をどう引き継ぐのかという問題があった。

これに関し、ビルド17063 から、WSLENV という環境変数が加わり 、パス変換のルールを指定できるようになった。

詳しくはリンク先を参照のこと。


Hyper

Hyper は、Windows でも動くクロスプラットフォームなターミナル。

https://hyper.is/

https://github.com/zeit/hyper

Powershell などを使う上でも素晴らしいターミナルであるが、今回は WSL と一緒に使う事を前提に設定していく。


インストール

scoop や Chocolatey でも提供されているので、簡単に入る。

PS> scoop install hyper

or

PS> choco install hyper


設定

Hyper の設定は ~/.hyper.js で全て管理されているので、それを編集して設定を行う。

自分はこんな感じ。


.hyper.js

...

- fontSize: 12,
+ fontSize: 16,

- cursorBlink: false,
+ cursorBlink: true,

- copyOnSelect: false
+ copyOnSelect: true

- shell: '',
+ shell: 'C:\\Windows\\System32\\wsl.exe',

...



フォント

フォントは MyricaM を使っている。

プログラミングフォント Myrica / Estable

Powerline 化は、以下リポジトリの手順を参考にした。

tsunesan3/awsome-jp-coding-fonts


.hyper.js

...

- fontFamily: 'Menlo, "DejaVu Sans Mono", Consolas, "Lucida Console", monospace',
+ fontFamily: 'MyricaM, Menlo, "DejaVu Sans Mono", Consolas, "Lucida Console", monospace',

...



プラグイン

Hyper はプラグインで拡張することで機能を追加していく。

とは言え、現在は Hyper 2.0 移行期で未対応が多かった り、 Windows 対応が悲惨なことになっていたり と、胸が締め付けらる思いがする。


ウィンドウ

最前面固定のために、hyper-always-on-top を入れている。

背景透過もやりたかったが、hyper-transparenthyper-transparent-dynamic も上手く動作しない。


ステータスバー

大人気の hyperline は残念ながら Windows 未対応

今は hyper-statusline を使っている。が。これも WSL だと Git 管理下なのに Git 情報が表示されなかったりと不安定。


タブ

タブ機能の強化としては hyper-tabs-enhanced が便利だが、Windows で CPU 使用率が異常に上がる 問題があり、使えない。


テーマ

テーマも Plugin として導入ができる。

自分は、hypermaterial-vibrancy とか hyper-material-theme を使ったりいる。


Explorer 統合

Windows を使っていると、フォルダを右クリックして Open with Hyper とかしたくなる。

インストールすると追加してくれるらしいが、自分が scoop で入れたときはなかった。

ので、自分で入れた。


hyper_integration.reg

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\Hyper]
"Icon"="C:\\Users\\<< YOUR_NAME >>\\scoop\\apps\\hyper\\current\\Hyper.exe,0"
@="Open Hyper here"

[HKEY_CLASSES_ROOT\Directory\Background\shell\Hyper\command]
@="C:\\Users\\<< YOUR_NAME >>\\scoop\\apps\\hyper\\current\\Hyper.exe \"%V\""

[HKEY_CLASSES_ROOT\Directory\shell\Hyper]
@="Open Hyper here"
"Icon"="C:\\Users\\<< YOUR_NAME >>\\scoop\\apps\\hyper\\current\\Hyper.exe,0"

[HKEY_CLASSES_ROOT\Directory\shell\Hyper\command]
@="C:\\Users\\<< YOUR_NAME >>\\scoop\\apps\\hyper\\current\\Hyper.exe \"%V\""


こんな感じで追加することで登録できた。


Tips


Copy / Paste

Ctrl+Shift+C / Ctrl+Shift+V で可能


fish shell

細かな設定を行わなくても最初からそれなりに使える Shell。ものぐさな自分に最適。

image.png

https://fishshell.com/

Windows ではなく Linux を主軸に置きたいと思った要因として、fish があるから というのは大きい。


インストール

※ 以下、WSL 上で実行している

なぜか GPG エラーで鍵追加できなかったので、ビルドする。

# 最新のソースを取得

$ cd ~
$ git clone https://github.com/fish-shell/fish-shell && cd fish-shell

# インストール
$ mkdir -p build && cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ make
$ sudo make install
$ rm -rf fish-shell


.hyper.js

...

- shellArgs: [],
+ shellArgs: ['fish'],

...



設定

fish の設定は、~/.config/fish/config.fish に書く。


config.fish

# お好みのカスタマイズ

alias ls='exa -l'
alias grep='rg'
alias cat='bat'
function zz
set p (z -l | awk '{ print $2 }' | fzf)
if test $status -eq 0
cd $p
else
return
$status
end
end

# Windows 側の Explorer で起動するコマンド
alias ii='explorer.exe'

# Windows のパスに合わせて移動するための関数
function wcd
if [ $argv[1] = "/" ]
cd /mnt/c
else if [ $argv[1] = ~ ]
cd /mnt/c/users/<<User Name>>
else
cd /mnt/c/
$argv[1]
end
end



プラグイン

プラグインを管理するために、fisherman を導入する。

https://github.com/fisherman/fisherman

# fisher 導入

$ curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs https://git.io/fisher

# 好きな Plugin 導入
$ fisher z fzf edc/bass spin 0rax/fish-bd


テーマ

fish のテーマも入れとく。

bobthefish はなぜか Powerline が出なかったので、諦めて agnoster にした。


悩みどころ


Q. WSL は普通の Linux として使えるのか

A. そんなことはない

などなど。再構築を初めてから数ヶ月。その間に引っかかった点だけでもこれだけあった。

とは言え、あまり悲観はしていなくて、むしろすごいスピートで改善している事に驚く

ファイルシステム辺りはある程度は諦めるとしても、それ以外はそのうち解決してくれるだろうと思ってる。


Q. パフォーマンスはどうなのか



  • vs Windows 向けバイナリ


    • やっぱりファイル IO 系が遅い?



      • node/nodejs リポジトリの git status は WSL の方が 3 倍遅かった

      • ripgrep で rg -t yaml hoge -l とかすると、ほとんど変わらない ( というか早すぎて良く分からん )



    • ツールの癖をつかめば、上手く並行運用はできそう




  • vs VM, Docker



    • この記事で検証されている が、VM と比べると相当遅いらしい。

    • やはり本格的な開発環境構築などを考えると、まだまだなんだろうか。



A. 諦めも肝心。癖を掴み、遅いものは大人しく Windows ネイティブ or VM, Docker を使おう。


Q. 開発環境はどちらで作るべきか

image.png

これを見れば分かるように、今は Windows 側と Linux 側、どちらにも Node.js が入っている。

さて、日々の開発はどちらですべきなのだろうか。

A. (暫定) とりあえずどっちも入れておいて、適宜変える。

これに関しては、Docker や VM なども考慮しベストを探す必要があるので、また別の機会に考える。


感想

使い慣れた Linux Distribution・Shell の使い心地で Windows ファイルシステムが操作できる という点ではとても良い。

本格的に Linux を使いたいのであれば、足りない部分はどうしても感じてしまう。

そこは無理せず、Docker や VM と併用する必要があるだろう。


参考