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もあります.