nushellはrust製のクロスプラットフォームなシェルで,特徴として全ての出力に型が付いていることがあげられます.wingetやchocolateyなどのパッケージマネージャーを用いてインストールできます.
コマンドの利用
コマンドはnushellで独自に定義されており,パイプラインを用いて次々と処理していくことができます.例えば
〉ls
╭───┬────────────┬──────┬───────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼────────────┼──────┼───────┼──────────────┤
│ 0 │ .gitignore │ file │ 8 B │ 18 hours ago │
│ 1 │ Cargo.lock │ file │ 156 B │ 18 hours ago │
│ 2 │ Cargo.toml │ file │ 181 B │ 18 hours ago │
│ 3 │ src │ dir │ 0 B │ 18 hours ago │
│ 4 │ target │ dir │ 0 B │ 18 hours ago │
│ 5 │ utils.nu │ file │ 956 B │ 2 hours ago │
╰───┴────────────┴──────┴───────┴──────────────╯
のような出力に対してインデックスを指定することでファイルの情報を取得できます.これはlsがテーブルを返すためです.
〉ls | get 2
╭──────────┬──────────────╮
│ name │ Cargo.toml │
│ type │ file │
│ size │ 181 B │
│ modified │ 18 hours ago │
╰──────────┴──────────────╯
コマンドの結果を別のコマンドの引数として利用する場合は()でくくります.以下の例ではlsで取得した0番目のディレクトリであるsrcに移動しています.
〉ls | where type == dir
╭───┬────────┬──────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼────────┼──────┼──────┼──────────────┤
│ 0 │ src │ dir │ 0 B │ 18 hours ago │
│ 1 │ target │ dir │ 0 B │ 18 hours ago │
╰───┴────────┴──────┴──────┴──────────────╯
〉cd (ls | where type == dir | get 0.name)
外部コマンドと併用
()を用いることで外部コマンドの引数としても結果を利用できます.例えばcargo runコマンドで以下のsrc/binディレクトリにあるhoge.rsをコンパイルして実行したい時,通常はcargo run --bin hogeとしますが
.
├ src
│ ├ main.rs
│ └ bin
│ ├ fuga.py
│ ├ hoge.rs
│ └ piyo.rs
├ target
├ Cargo.toml
└ Cargo.lock
fn main() {
println!("Hello, world! hoge");
}
以下のようにすることでlsの結果の番号で指定できます.
〉ls src/bin
╭───┬─────────────────┬──────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼─────────────────┼──────┼──────┼──────────────┤
│ 0 │ src\bin\fuga.py │ file │ 0 B │ 3 hours ago │
│ 1 │ src\bin\hoge.rs │ file │ 53 B │ 19 hours ago │
│ 2 │ src\bin\piyo.rs │ file │ 54 B │ 3 hours ago │
╰───┴─────────────────┴──────┴──────┴──────────────╯
〉cargo run --bin (ls src/bin | get 1.name | path parse | get stem)
Hello, world! hoge
先ほどの処理に加えて パスを構造体(レコード)に変換,stemを取得しています.
カスタムコマンドの定義
カスタムコマンドはシェル上でも定義できますが,今回はファイルで定義します.lsのうち.rsファイルのみを返すコマンドls-rsは以下のように定義できます.
export def ls-rs [pattern?] {
if ($pattern == null) {
ls | where name ends-with ".rs"
} else {
ls $pattern | where name ends-with ".rs"
}
}
引数や変数として利用する場合は変数名に$を付けます.またpattern?のように?を付けることでオプションの引数を定義でき,引数が渡されなかった場合は値がnullあるは$nothingとなります.引数の型は指定しない場合anyになりますが,今回はglobで指定しても大丈夫です.
定義したコマンドをシェルで利用する場合はsource utils.nuとします.
〉source utils.nu
〉ls-rs src/bin
╭───┬─────────────────┬──────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼─────────────────┼──────┼──────┼──────────────┤
│ 0 │ src\bin\hoge.rs │ file │ 53 B │ 19 hours ago │
│ 1 │ src\bin\piyo.rs │ file │ 54 B │ 3 hours ago │
╰───┴─────────────────┴──────┴──────┴──────────────╯
単に.nuファイルを実行する場合はnu utils.nuとしますが,sourceを用いることでファイルで定義したコマンドや環境変数がシェルでも維持されます.またuseを用いることでも利用が可能です.
〉use utils.nu
〉utils ls-rs src/bin
╭───┬─────────────────┬──────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼─────────────────┼──────┼──────┼──────────────┤
│ 0 │ src\bin\hoge.rs │ file │ 53 B │ 19 hours ago │
│ 1 │ src\bin\piyo.rs │ file │ 54 B │ 3 hours ago │
╰───┴─────────────────┴──────┴──────┴──────────────╯
useはファイルをモジュールとして利用するため,ファイル内でコマンドの実行や環境変数への代入はできずコマンドやエイリアスなどの定義のみ可能です.またuseでインポートするコマンドにはexportを付ける必要があり,付けないものはファイルのローカルのコマンドとなります.
次にcargo runで用いたコマンドをカスタムコマンドとして定義してみます.先ほどのコマンドの定義とは異なり""で囲むことでスペースの空いたサブコマンドとして定義できます.ここでは引数patternにデフォルト値を与えています.そしてstemをechoするフラッグも引数としています.引数の横のコメントはhelpコマンドや-hフラッグを使ったときに表示されます.
export def "stem ls" [
number: int # Row number
pattern="./" # The glob pattern to use
--echo # Echo the stem string
] {
let stem_str = ( ls $pattern | get $number | get name | path parse | get stem)
if $echo { echo $stem_str }
$stem_str
}
これで以下のようにcargo runが使えます.
〉ls src/bin
╭───┬─────────────────┬──────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼─────────────────┼──────┼──────┼──────────────┤
│ 0 │ src\bin\fuga.py │ file │ 0 B │ 4 hours ago │
│ 1 │ src\bin\hoge.rs │ file │ 53 B │ 20 hours ago │
│ 2 │ src\bin\piyo.rs │ file │ 54 B │ 3 hours ago │
╰───┴─────────────────┴──────┴──────┴──────────────╯
〉cargo run --bin (stem ls 1 src/bin)
Hello, world! hoge
これでもいいのですが,オプション引数を後ろに持ってくるために引数の順番が直感的では無かったり,ls src/bin | sort-by name | stem 1のようにパイプラインで用いることができません.
nushellではパイプラインで渡された値を$inで利用できるため,以下のように改良できます.
export def stem [
number: int # Row number
--echo # Echo the stem string
] {
let stem_str = ($in | get $number | get name | path parse | get stem)
if $echo {echo $stem_str}
$stem_str
}
以下のようにパイプラインで利用できます.
〉ls src/bin | sort-by modified
╭───┬─────────────────┬──────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼─────────────────┼──────┼──────┼──────────────┤
│ 0 │ src\bin\hoge.rs │ file │ 53 B │ 20 hours ago │
│ 1 │ src\bin\fuga.py │ file │ 0 B │ 5 hours ago │
│ 2 │ src\bin\piyo.rs │ file │ 54 B │ 4 hours ago │
╰───┴─────────────────┴──────┴──────┴──────────────╯
〉cargo run --bin (ls src/bin | sort-by modified | stem 0 --echo)
hoge
Hello, world! hoge
シェルの起動時に読み込む
シェルの起動時に読み込むファイルとしてenv.nuとconfig.nuがあり,それぞれ$nu.env-pathと$nu.config-pathでそのパスを出力できます.そのconfig.nuに先ほど作成したutils.nuを読み込ませれば,ls-rsやstemをどこからでも利用できるようになります.
具体的には,config.nuと同じディレクトリにutils.nu を移動し以下を追記するだけです.
source utils.nu
他にもpythonにおける仮想環境のような仕組みであるoverlaysもあります.