Rust製のシェル Nushell を試してみた
しばたです。
ブログのネタ探しのためにネットサーフィンをしていたところRust製のNushellと呼ばれるシェルがある事を知りました。
作者によるイントロダクションは以下。
- Introducing nushell (ドメイン変更済み)
こちらのシェルは
A modern shell for the GitHub era
とあり、組み込みでGit連携できたりと新しめの機能を導入しているシェルなのですが、私が特に目を引いたのが、
(https://github.com/nushell/nushell
より)
Nu draws inspiration from projects like PowerShell, functional programming languages, and modern cli tools.
の一文で、PowerShellおじさんとしては「これは試さなければならぬ!」という気持ちになった次第です。
Nushellのステータス
このNushellですが、GitHubの説明に
This project has reached a minimum-viable product level of quality.
とある様に現時点では最小限の機能のみ実装された状態で、バージョンとしては本日時点でVer.0.2.0となります。
検証環境
ここからは実際にNushellを試してPowerShellとの比較をしてみたいと思います。
検証環境としては私の開発機である64bit版Windows 10 May 2019 Update(1903)を使いました。
インストール方法
GitHub上にWindows向けのバイナリが公開されていますので、ダウンロードして適当なディレクトリに展開します。
現在のバージョンはVer.0.2.0です。
今回はC:\Program Files2\nushell
フォルダに展開しています。
試してみた
展開したファイルのうち、nu.exe
がシェル本体ですのでダブルクリックして起動します。
特に初期処理などは無くいきなりCUIコンソールが表示されます。
基本的にはコマンドプロンプトと互換がある様でver
やmklink
といったコマンドプロンプトの内部コマンドが使えます。
ここからはNushell独自の機能を試していきます。
Git連携
Nushellは標準でGit連携する様になっており、Gitでソース管理しているディレクトリに移動すると現在のブランチを表示してくれます。
git-prompt.shやposh-gitにあるアレですね。
残念ながら現時点ではファイルの更新状況を表示したり、gitコマンドに対するCompleterといった機能はない様です。
内部コマンドとオブジェクト
次にNushellではls
といった独自の内部コマンドを持ち、この内部コマンドはPowerShellの様に型を持ったデータを返します。
たとえば、以下の様に
# Nushellにおいて ls は内部コマンド
ls
とだけ打つと、下図の様に表形式でディレクトリ・ファイル情報が表示されますが、この実体はテキストではなくオブジェクトです。
このオブジェクトはPowerShellと同じ様にパイプラインで操作することが可能です。
たとえば
ls | where type == Directory
とするとディレクトリだけを抽出、
さらに
ls | where type == Directory | pick name
とするとディレクトリのName
カラムを抽出することができます。
PowerShellに親しんでいる人間からすると非常に馴染みのある感じです。
ちなみにPowerShellで同様のことをする場合は、
dir | where { $_.PsIsContainer } | Select-Object Name
といった感じのコードになります。
内部コマンドの一覧
現在ある内部コマンドの一覧はGitHubをご覧ください。
PowerShellのGet-Command
に相当する内部コマンドを検索するコマンドはまだ無い様です。
オブジェクトの一覧
PowerShellは.NET Framework/.NET Core製で全てが.NETの型を持つオブジェクトから構成されていますが、Nushellでは幾つかのプリミティブな型と構造化データとなるObject
とList
でオブジェクトは構成されています。
オブジェクトの一覧は以下のドキュメントに記載されており、
プリミティブな型は
型 | 内容 | 備考 |
---|---|---|
Integer | 整数 | ソースを見る限り内部的にはi64 |
Float | 小数 | ソース上見る限り内部表記および内部型はDecimal |
String | 文字列 | |
Boolean | 真偽値 | |
Date | 日付・時刻 | タイムゾーンを内包する |
Path | ファイルパス | ソースを見る限り内部的にはPathBuf |
Byte | kb、mbなどの単位を持った整数 | ソースを見る限り内部的にはu64 |
構造化データは
型 | 内容 | 備考 |
---|---|---|
Objects | 子要素を持つオブジェクト型 | 内部的にはDictionaryらしい |
Binary | バイナリデータ | 内部的にはVec<u8> |
List | リスト型 | すべてがListでArrayは無い様にみえる |
Block | コードブロック |
が定義されています。
ちなみにソース的には以下の様に定義されていました。
pub enum Primitive {
Nothing,
Int(i64),
#[allow(unused)]
Float(OF64),
Bytes(u64),
String(String),
Boolean(bool),
Date(DateTime<Utc>),
Path(PathBuf),
// Stream markers (used as bookend markers rather than actual values)
BeginningOfStream,
EndOfStream,
}
// ・・・中略・・・
pub enum Value {
Primitive(Primitive),
Object(crate::object::Dictionary),
#[serde(with = "serde_bytes")]
Binary(Vec<u8>),
List(Vec<Tagged<Value>>),
#[allow(unused)]
Block(Block),
}
私はRustは全然できませんが、これだけでもなんとなくオブジェクトの実体の予想はつくかと思います。
パイプライン
Nushellではパイプラインの扱いについて以下のドキュメントにまとめられており、
コマンドの組み合わせ方による挙動が定義されています。
内部コマンド | 外部コマンド
でパイプする場合- 内部コマンドで発生した"Data"(オブジェクト)は文字列として標準出力に出力される。
外部コマンド | 内部コマンド
でパイプする場合- 外部コマンドの出力は"1つ"の文字列として内部コマンドに渡される
外部コマンド1 | 外部コマンド2
でパイプする場合- 外部コマンド1の標準出力と外部コマンド2の標準入力を接続し直接データをパイプさせる
この挙動をPowerShellと比較すると3.
のパターンの挙動が大きく異なります。
PowerShellの場合は外部コマンド1 | 外部コマンド2
でパイプする場合でもストリーム介することになり、外部コマンド1 -> "ストリーム" -> 標準出力 -> 標準入力 -> 外部コマンド2
という経路でデータが流れてしまいます。
このためPowerShellにおいては外部コマンド同士のパイプラインがユーザーの期待した動作にならないことが非常に多い現状があります。
PowerShell Core 6.0で若干改善されてはいるのですが根本的な挙動に変わりはなく、この外部コマンド同士のパイプはPowerShellにおける大きな弱点なのですが、Nushellではこの部分はうまく対処されている感じです。
Shells
Nushell独自の機能としてShellsというものがあります。
enter
コマンドで新しいシェルを立ち上げ、いわゆる"screen"コマンドの代替となる様な機能なのですが、個人的にはあまりうま味がわかりませんでした...
shells
コマンドで現在立ち上がっているシェルの一覧を参照できます。
シェルの切り替えはp
やn
コマンド、シェルを終了するときはexit
コマンドを使います。
Plugins
今回は試しませんでしたがNushellはプラグイン機構を持ち独自の機能を追加できる様になっているそうです。
仕様としてはnu_plugin_[コマンド名]
といった名前の実行ファイルを作れば良いそうで、GitHubのpluginsフォルダにある実装を参考に作れるとのことです。
最後に
以上、簡単ですがNushellを触ってみた感想となります。
PowerShellは 全て が.NETのオブジェクトから構成されており、それがPowerShellの強みであるものの独特のクセや外部コマンドとの連携の弱さとなっている部分があります。
Nushellではオブジェクトの使用は限定的・選択的であり、オブジェクトを使うところを都度考えないといけない面倒さはありますが、その分クセは少なく外部コマンドとの連携もしやすいのかなと思いました。
最初に説明したとおり出来たばかりのシェルで機能的に不足している部分はまだまだありますが今後の発展に期待していきたい感じです。