11
4

More than 1 year has passed since last update.

Nushell が Elixir っぽくってワクワクした

Last updated at Posted at 2023-03-18

はじめに

私は寡聞にして存じなかったのですが、 先日 Nushell なるものを教えてもらいました

Qiita にも既にいくつも記事があるし、 2019 年からあるものなので今更感が強いですが、使ってみると何とも Elixir で、アルケミスト的にワクワクしたので記事にしておきます

(Rust 製だけど)

インストール

macOS の場合、 Homebrew でインストールできます

brew install nushell

Windows の場合は winget です

winget install nushell

ログインシェルとして設定する方法も記載されていますが、推奨はされていません

Nushell の開始

お使いのターミナル(iTerm2warpWindows Terminal)から nu を実行しましょう

nu

スクリーンショット 2023-03-18 11.42.12.png

すると Nushell の DiscordGitHub などなどが表示されて Nushell の世界に入ります

Nushell の基本

ファイル一覧

まずファイル一覧を出してみましょう

ls

スクリーンショット 2023-03-18 11.55.43.png

特にオプション等指定せずとも良い感じにテーブル表示してくれます

ではパイプラインを使ってみましょう

以降、画像ではなくテキストで実行結果を貼り付けます

容量制限が怖いので

$ ls | sort-by size | reverse
╭───┬─────────┬──────┬──────────┬───────────────╮
│ # │  name   │ type │   size   │   modified    │
├───┼─────────┼──────┼──────────┼───────────────┤
│ 0 │ 002.txt │ file │   3.0 MB │ 6 minutes ago │
│ 1 │ 003.txt │ file │ 608.3 KB │ 8 minutes ago │
│ 2 │ 011.txt │ file │   1.7 KB │ 8 minutes ago │
│ 3 │ yyy     │ dir  │    160 B │ 3 minutes ago │
│ 4 │ xxx     │ dir  │    128 B │ 3 minutes ago │
│ 5 │ 001.txt │ file │     16 B │ 9 minutes ago │
╰───┴─────────┴──────┴──────────┴───────────────╯

「ファイル一覧を取得して」 | 「サイズ順に並び替えて」 | 「順序を逆にする」というのが直感的にわかりますね

通常の bash だと以下のようになります

$ ls -lhS
total 7608
-rw-r--r--  1 oec  staff   2.9M  3 18 11:50 002.txt
-rw-r--r--  1 oec  staff   594K  3 18 11:48 003.txt
-rw-r--r--  1 oec  staff   1.7K  3 18 11:48 011.txt
drwxr-xr-x  5 oec  staff   160B  3 18 11:53 yyy
drwxr-xr-x  4 oec  staff   128B  3 18 11:53 xxx
-rw-r--r--  1 oec  staff    16B  3 18 11:47 001.txt

短いことこそが価値である場合」には良いですが、オプションを覚えていないと全く理解できませんね

ちなみにファイルサイズが違うのは、 1,024 で割っているか 1,000 で割っているかの違いです

1,024 で割った方(bash の表現)は厳密には KiB (キビバイト)ですね

続いてフィルターです

$ ls | where size > 1kb
╭───┬─────────┬──────┬──────────┬────────────────╮
│ # │  name   │ type │   size   │    modified    │
├───┼─────────┼──────┼──────────┼────────────────┤
│ 0 │ 002.txt │ file │   3.0 MB │ 21 minutes ago │
│ 1 │ 003.txt │ file │ 608.3 KB │ 23 minutes ago │
│ 2 │ 011.txt │ file │   1.7 KB │ 22 minutes ago │
╰───┴─────────┴──────┴──────────┴────────────────╯

サイズが 1 KBより大きいものを抽出する、というのが読み取れます

ちなみに bash だと以下のようになります

$ find . -maxdepth 1 -type f -size +1k | xargs ls -ldh
-rw-r--r--  1 oec  staff   2.9M  3 18 11:50 ./002.txt
-rw-r--r--  1 oec  staff   594K  3 18 11:48 ./003.txt
-rw-r--r--  1 oec  staff   1.7K  3 18 11:48 ./011.txt

最早読めというのが無茶だし、ググらずに書くのは私には不可能です

プロセス一覧

プロセスの一覧を表示したり、特に重い処理を探したりするのも楽チンです

$ ps | where cpu > 5
╭───┬───────┬────────────────────┬─────────┬───────┬──────────┬─────────╮
│ # │  pid  │        name        │ status  │  cpu  │   mem    │ virtual │
├───┼───────┼────────────────────┼─────────┼───────┼──────────┼─────────┤
│ 0 │ 75346 │ nu                 │ Running │  9.87 │  13.3 MB │ 35.0 GB │
│ 1 │ 61476 │ iTerm2             │ Sleep   │ 15.09 │ 125.8 MB │ 35.7 GB │
│ 2 │  3572 │ qemu-system-x86_64 │ Sleep   │  8.69 │ 481.2 MB │ 48.2 GB │
╰───┴───────┴────────────────────┴─────────┴───────┴──────────┴─────────╯

現在時刻の取得

現在時刻も分かりやすく date now で取得できます

$ date now
Sat, 18 Mar 2023 12:23:16 +0900 (now)

システム情報の取得

sys で OS などの情報を取得することができます

これは実行結果が大きすぎるため実際の実行結果は貼り付けませんが、以下のような形式になっています

╭───────┬───────────────────╮
│ host  │ {record 6 fields} │
│ cpu   │ [table 4 rows]    │
│ disks │ [table 3 rows]    │
│ mem   │ {record 4 fields} │
│ temp  │ [table 1 row]     │
│ net   │ [table 4 rows]    │
╰───────┴───────────────────╯

つまり、 Elixir でいうところの Map になっています

では host のところだけ取り出してみます

$ sys | get host
╭─────────────────┬───────────────────────────╮
│ name            │ Darwin                    │
│ os_version      │ 13.2.1                    │
│ long_os_version │ MacOS 13.2.1              │
│ kernel_version  │ 22.3.0                    │
│ hostname        │ xxxxx                     │
│ uptime          │ 1wk 1day 13hr 56min 51sec │
│ boot_time       │ 2023-03-09T22:38:35+09:00 │
| sessions        | [table 3 rows]            |
╰─────----------──┴──--------─────────────────╯

| get host で取得できます Elixir でいうところの |> Map.get(:host) ですね

実際には sessions の右側にテーブルでセッションの一覧が表示されます

更に OS バージョンだけを取得したい場合は以下のようになります

$ sys | get host.os_version
13.2.1

以下のように実行することで、現在システムにログインしているユーザーの一覧が取得できます

$ sys | get host.sessions.name
╭───┬──────────────╮
│ 0 │ _mbsetupuser │
│ 1 │ oec          │
│ 2 │ root         │
╰───┴──────────────╯

そして、ここからが Elixir like というか関数型っぽさというかです

List の各値に対してコマンドを適用することができます

$ sys | get host.sessions.name | each { |it| ^echo $it }
_mbsetupuser
oec
root

アルケミストの皆さんは、この each が Elixir でいうところの Enum.map であることが分かりますね

map がなくて each な点に注意

each {|各値を表す変数名| 実行したいコマンド} で List の各値にコマンドを適用します

上の例で ^echo のように ^ (ハット)が付いているのは、 Nushell の echo ではなく、通常の echo を使わせる為です( ^ がないとテーブル表示になる)

当然、 each があれば reduce もあるわけで、つまりこれを使えば関数型っぽく何でも処理できるわけです

reduce

例えば .txt ファイルの合計サイズは以下のようにして算出できます(もっと別の方法もあると思いますが)

$ ls | where name =~ ".txt" | reduce -f 0b {|it, acc| $acc + $it.size}
3.7 MB

each {|各値を表す変数名, 前の実行結果を表す変数名| 実行したいコマンド} で List の各値毎に再帰的にコマンドを適用していき、最終結果を取得します

-f で acc (前の実行結果)の初期値を 0 バイト(ファイルサイズ型)に指定しています

スクリプト

もちろん、スクリプトとして実行することもできます

以下のような内容のファイルを text_sum.nu という名前で保存しましょう

#!/usr/bin/env nu

ls
| where name =~ ".txt"
| reduce -f 0b {|it, acc| $acc + $it.size}
| format filesize MB

実行権限を付けておきます

chmod +x text_sum.nu

これで .txt を含むファイルの合計サイズを MB 単位で出力してくれます

以下のようにして実行できます

$ nu test_sum.nu
3.7 MB

また、先頭にシバン(#!/usr/bin/env nu)をつけたので、単に ./test_sum.nu で実行することも可能です

特にパイプで改行するとき \ によるエスケープが不要なのが良いですね

最早 Elixir と全く同じ感覚で書けます

まとめ

Nushell は手早くファイルを探索したり操作したりするとき、結構使えそうです

また、Elixir のような書き方は可読性が高く、データ処理の記述に向いていることが再認識できました

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4