|
| 1 | +--- |
| 2 | +cover: false |
| 3 | +title: 'Nushell, after 8 months' |
| 4 | +description: "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" |
| 5 | +date: 2024-04-29 11:15:00 |
| 6 | +tags: ['shell', 'nushell', 'cli', 'unix', 'powershell'] |
| 7 | +--- |
| 8 | + |
| 9 | +> ... 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. |
| 10 | +
|
| 11 | +[Me, 8 months ago](https://okmanideep.me/i-am-very-excited-about-using-nushell-everyday/) |
| 12 | + |
| 13 | +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](https://youtu.be/-6BsiVyC1kM?si=w1U3f4OzdOAT6C55). 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. |
| 14 | + |
| 15 | +## Surprisingly seamless 🧈 |
| 16 | +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. |
| 17 | + |
| 18 | +Let's take an example. Get the first pod's name with the status `Running` in a kubernetes cluster and enter it's shell? |
| 19 | + |
| 20 | +```sh |
| 21 | +$ kubectl -n namespace get pods |
| 22 | +``` |
| 23 | +gets you a table like this |
| 24 | + |
| 25 | +``` |
| 26 | +NAME READY STATUS RESTARTS AGE |
| 27 | +namespace-86c7df9555-4n9cc 1/1 Running 0 2d2h |
| 28 | +namespace-86c7df9555-65nks 1/1 Running 0 2d2h |
| 29 | +namespace-86c7df9555-cdzll 1/1 Running 1 (35h ago) 2d1h |
| 30 | +namespace-86c7df9555-dlpnx 1/1 Running 0 35h |
| 31 | +namespace-86c7df9555-fnrgd 1/1 Running 0 2d2h |
| 32 | +namespace-86c7df9555-lnx2v 1/1 Running 0 2d1h |
| 33 | +namespace-86c7df9555-nmwrx 1/1 Running 0 2d2h |
| 34 | +namespace-86c7df9555-xv45m 1/1 Running 0 35h |
| 35 | +``` |
| 36 | +This is just plain text but pipe it into `detect columns` and we get an actual `nushell` table |
| 37 | + |
| 38 | +```sh |
| 39 | +$ kubectl -n namespace get pods | detect columns |
| 40 | +``` |
| 41 | + |
| 42 | +<img src="https://imgur.com/9lVQPJ0.png" style="max-width: 600px;" /> |
| 43 | + |
| 44 | +Now we can filter the rows with `where` and get the first row with `first` |
| 45 | + |
| 46 | +```sh |
| 47 | +$ kubectl -n namespace get pods | detect columns | where { $it.STATUS == "Running" } | first | get NAME |
| 48 | +``` |
| 49 | +
|
| 50 | +We can store this in a variable and access the shell with `kubectl exec` |
| 51 | +
|
| 52 | +```sh |
| 53 | +$ let pod_id = kubectl -n namespace get pods | detect columns | where { $it.STATUS == "Running" } | first | get NAME |
| 54 | +$ kubectl -n namespace exec -it $pod_id -- /bin/bash |
| 55 | +``` |
| 56 | +
|
| 57 | +Or just put it in `()` brackets and use it directly |
| 58 | +
|
| 59 | +```sh |
| 60 | +$ kubectl -n namespace exec -it (kubectl -n namespace get pods | detect columns | where { $it.STATUS == "Running" } | first | get NAME) -- /bin/bash |
| 61 | +``` |
| 62 | +
|
| 63 | +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. |
| 64 | +
|
| 65 | +## Perfect for data wrangling ⚙️ |
| 66 | +Lately I have been working with some csv files and what a delight it has been to work with them in `nushell`. |
| 67 | +
|
| 68 | +Colleague pings me saying "Here are the leads we want to add to the database - leads.csv". |
| 69 | +
|
| 70 | +I take a look at the file and there are some invalid user_ids in the file. |
| 71 | +
|
| 72 | +```sh |
| 73 | +open leads.csv | where { ($it.user_id | describe) != 'int' } | count |
| 74 | +``` |
| 75 | +I inform him - "Hey, we have 32 invalid user_ids in the leads.csv file. I will ignore them for now." and move on. |
| 76 | +
|
| 77 | +```sh |
| 78 | +open leads.csv | where { ($it.user_id | describe) == 'int' } | get user_id | str join ',' | pbcopy |
| 79 | +``` |
| 80 | +(Copies the user_ids to the clipboard) |
| 81 | +
|
| 82 | +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. |
| 83 | +
|
| 84 | +By the way, if I want to convert that CSV to JSON? |
| 85 | +
|
| 86 | +```sh |
| 87 | +open leads.csv | to json | pbcopy |
| 88 | +``` |
| 89 | +Ready to just paste it into a node REPL. |
| 90 | +
|
| 91 | +This works with CSV, JSON, YAML, TOML, SQLite and [many more formats](http://www.nushell.sh/book/loading_data.html#opening-files). This came in handy to check which exact version of package is being used in a `package-lock.json` file a number of times. |
| 92 | +
|
| 93 | +```sh |
| 94 | +open package-lock.json | get dependencies | get ws | get version |
| 95 | +``` |
| 96 | +
|
| 97 | +## It can't all be that good, can it? |
| 98 | +While I was about to adopt a new shell that's not 1.0 yet, I was expecting to deal with some rough edges. |
| 99 | +
|
| 100 | +> 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 |
| 101 | +
|
| 102 | +[Me, 8 months ago](https://okmanideep.me/i-am-very-excited-about-using-nushell-everyday/) |
| 103 | +
|
| 104 | +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. |
| 105 | +
|
| 106 | +[fnm](https://github.com/Schniz/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 |
| 107 | +
|
| 108 | +```sh |
| 109 | +# fnm - node version manager |
| 110 | +# https://dev.to/vaibhavdn/using-fnm-with-nushell-3kh1 |
| 111 | +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 }) |
| 112 | +
|
| 113 | +$env.PATH = ($env.PATH | prepend $"($env.FNM_MULTISHELL_PATH)/bin") |
| 114 | +``` |
| 115 | +
|
| 116 | +Essentially fake the shell, get the necessary changes and apply them to the `nushell` environment. |
| 117 | +
|
| 118 | +Some extra work to setup programs that output configuration for bash / zsh etc. And a few copy pasta for setting up some completions. |
| 119 | +
|
| 120 | +That's about it. After I have setup `nushell` in my system and added it to my [dotfiles](https://github.com/okmanideep/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`. |
0 commit comments