Nushell, after 8 months

... Plain text is definitely simpler than tables. So maybe we are just moving complexity here. Or this is a very good abstraction and a lot of things improve. Time will tell.

Me, 8 months ago

And the last 8 months have told me - Tables are a very good abstraction for CLI. No doubt. Possibly because they retain the fundamental nature of Values. In fact, tables are already present in unix shell, hiding in plain text. ps, ll, kubectl and many more programs have a tabular output. And to do anything with them, it's a lot more easier in nushell than in bash or similar shells.

Surprisingly seamless 🧈

I had my concerns initially - "Won't I face a lot of issues with all the unix programs, that just expect plain text and output plain text?". But it's barely been a problem. nushell's inbuilt commands and operators just take care of converting plain text to structured data and extract the necessary values to pipe them back into other programs.

Let's take an example. Get the first pod's name with the status Running in a kubernetes cluster and enter it's shell?

$ kubectl -n namespace get pods

gets you a table like this

NAME                                                 READY   STATUS      RESTARTS      AGE
namespace-86c7df9555-4n9cc                             1/1     Running     0             2d2h
namespace-86c7df9555-65nks                             1/1     Running     0             2d2h
namespace-86c7df9555-cdzll                             1/1     Running     1 (35h ago)   2d1h
namespace-86c7df9555-dlpnx                             1/1     Running     0             35h
namespace-86c7df9555-fnrgd                             1/1     Running     0             2d2h
namespace-86c7df9555-lnx2v                             1/1     Running     0             2d1h
namespace-86c7df9555-nmwrx                             1/1     Running     0             2d2h
namespace-86c7df9555-xv45m                             1/1     Running     0             35h

This is just plain text but pipe it into detect columns and we get an actual nushell table

$ kubectl -n namespace get pods | detect columns

Now we can filter the rows with where and get the first row with first

$ kubectl -n namespace get pods | detect columns | where { $it.STATUS == "Running" } | first | get NAME

We can store this in a variable and access the shell with kubectl exec

$ let pod_id = kubectl -n namespace get pods | detect columns | where { $it.STATUS == "Running" } | first | get NAME
$ kubectl -n namespace exec -it $pod_id -- /bin/bash

Or just put it in () brackets and use it directly

$ kubectl -n namespace exec -it (kubectl -n namespace get pods | detect columns | where { $it.STATUS == "Running" } | first | get NAME) -- /bin/bash

Working within nushell has been a lot like working with the programming languages that I am used to. It feels like I am in a REPL of one of those languages. Familiar and comfortable.

Perfect for data wrangling ⚙️

Lately I have been working with some csv files and what a delight it has been to work with them in nushell.

Colleague pings me saying "Here are the leads we want to add to the database - leads.csv".

I take a look at the file and there are some invalid user_ids in the file.

open leads.csv | where { ($it.user_id | describe) != 'int' } | count

I inform him - "Hey, we have 32 invalid user_ids in the leads.csv file. I will ignore them for now." and move on.

open leads.csv | where { ($it.user_id | describe) == 'int' } | get user_id | str join ',' | pbcopy

(Copies the user_ids to the clipboard)

I can probably do the same with awk and sed in bash. But this is a lot more simpler for me. Possibly because I work with object oriented languages a lot. And commands like where, first, take, skip are very familiar to me because all the languages have adopted these functional paradigms for operating with collections / streams.

By the way, if I want to convert that CSV to JSON?

open leads.csv | to json | pbcopy

Ready to just paste it into a node REPL.

This works with CSV, JSON, YAML, TOML, SQLite and many more formats. This came in handy to check which exact version of package is being used in a package-lock.json file a number of times.

open package-lock.json | get dependencies | get ws | get version

It can't all be that good, can it?

While I was about to adopt a new shell that's not 1.0 yet, I was expecting to deal with some rough edges.

It feels like a pre-honeymoon phase with nu. So there is a lot of adulation right now. It's likely that there are a lot of sour learnings to follow

Me, 8 months ago

To be honest, I didn't have to deal with many issues. But there was one which took a bit of time to figure out.

fnm - fast node version manager, only offer setup instructions for bash, zsh, fish and powershell to add necessary changes to the shell profile for the right $PATH. For nushell, we have to use something like this

# fnm - node version manager
# https://dev.to/vaibhavdn/using-fnm-with-nushell-3kh1
load-env (/opt/homebrew/bin/fnm env --shell bash | lines | str replace 'export ' '' | str replace -a '"' '' | split column = | rename name value | where name != "FNM_ARCH" and name != "PATH" | reduce -f {} {|it, acc| $acc | upsert $it.name $it.value })

$env.PATH = ($env.PATH | prepend $"($env.FNM_MULTISHELL_PATH)/bin")

Essentially fake the shell, get the necessary changes and apply them to the nushell environment.

Some extra work to setup programs that output configuration for bash / zsh etc. And a few copy pasta for setting up some completions.

That's about it. After I have setup nushell in my system and added it to my dotfiles, it's been a smooth ride across both Windows and MacOS. I have been using nushell as my primary shell for the last 8 months and I don't see myself going back to bash or zsh or powershell.