Scripting is More Fun With Nushell
There are multiple ways to improve your experience in the terminal. You can get a nice prompt with starship. On Linux and macOS, you can switch to the fish shell. A lot of nice things like syntax highlighting, tab completion with help text and inline suggestions simply work out of the box.
However, I went for Nushell. Unlike fish, Nu also works on Windows. Nuโs interactive experience is nearly as nice as fishโs out-of-the-box and just as nice with a few configuration tweaks. Since I donโt use Windows as my daily driver that shouldnโt matter all that much to me, but it can be an extra benefit.
Another common way of use case of shells is for scripting.
After experimenting with commands in your terminal, you put the very same commands in a text file.
In the case of Nu, you then execute that script with nu script.nu
.
This is the workflow where shells shine, and Nu is a prime example for that.
So letโs take a look at the pitch on Nuโs homepage:
Nu pipelines use structured data so you can safely select, filter, and sort the same way every time. Stop parsing strings and start solving problems.
When I first read this, it didnโt really resonate with me. Maybe I didnโt write enough shell scripts at that time.
Extract the Top Issues From a Repository
Section titled โExtract the Top Issues From a RepositoryโLetโs look at a non-trivial example to find out why itโs a big deal that Nu deals with structured data. Some GitHub repositories like Zedโs have an issue that shows the issues with the highest number of ๐ reactions created within in the last week.
We will now do the same with the help of Nushell.
I will use the Pixi repository, but any other repository with enough community engagement will do as well.
let repo = "prefix-dev/pixi"
Many modern CLI tools have a JSON interface and gh
is not different.
We need the following fields:
createdAt
so we only take the ones from last weekreactionGroups
so we can extract the ๐ reactionstitle
andurl
to display them later
In the end we will get a list of records also known as a table. Each record represents one issue, and we pick one in order to get familiar with the structure. Please note that this will return a different issue for you, since more issues will have been opened on this repo by the time you read this.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| get 1
โญโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโ createdAt โ 2025-08-29T13:11:13Z โโ โ โญโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโฎ โโ reactionGroups โ โ # โ content โ users โ โโ โ โโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโค โโ โ โ 0 โ THUMBS_UP โ โญโโโโโโโโโโโโโฌโโโโฎ โ โโ โ โ โ โ โ totalCount โ 1 โ โ โโ โ โ โ โ โฐโโโโโโโโโโโโโดโโโโฏ โ โโ โ โฐโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโฏ โโ title โ Ability to split pixi.lock (not toml!) into multiple files โโ url โ https://github.com/prefix-dev/pixi/issues/4467 โโฐโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Notice that Nu pretty prints the record per default.
Only take Issues From Last Week
Section titled โOnly take Issues From Last WeekโNu also has first class support for datetime objects.
This makes it easy to only take the rows of our table where createdAt
falls within the last week.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| get createdAt| last 5
โญโโโโฌโโโโโโโโโโโโโโโโโโโโโโโฎโ 0 โ 2025-08-25T11:28:37Z โโ 1 โ 2025-08-25T10:19:22Z โโ 2 โ 2025-08-25T10:07:58Z โโ 3 โ 2025-08-25T07:21:52Z โโ 4 โ 2025-08-24T17:00:35Z โโฐโโโโดโโโโโโโโโโโโโโโโโโโโโโโฏ
We took the last 5 elements. Considering that this blog has been written on August 31st, these results seem pretty reasonable.
Extract the ๐ Reactions
Section titled โExtract the ๐ ReactionsโWe donโt have a nice way to extract the ๐ reactions yet, so letโs work on that.
As a reminder, thatโs how reactionGroup
value looks like for the issue we looked at originally.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| get 1| get reactionGroups
โญโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโฎโ # โ content โ users โโโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโคโ 0 โ THUMBS_UP โ โญโโโโโโโโโโโโโฌโโโโฎ โโ โ โ โ totalCount โ 1 โ โโ โ โ โฐโโโโโโโโโโโโโดโโโโฏ โโฐโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโฏ
This issue, however, does not have reactions at all.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| get 0| get reactionGroups
โญโโโโโโโโโโโโโฎโ empty list โโฐโโโโโโโโโโโโโฏ
Letโs insert a new column thumbsUp
, which is based on the column reactionGroup
.
Of this reaction table, it only takes rows with THUMBS_UP
reaction.
Rows that donโt have any THUMBS_UP
reactions will result in an empty list.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| insert thumbsUp { $in.reactionGroups | where content == THUMBS_UP}| get thumbsUp| first 5
โญโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโ 0 โ [list 0 items] โโ 1 โ โญโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโฎ โโ โ โ # โ content โ users โ โโ โ โโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโค โโ โ โ 0 โ THUMBS_UP โ โญโโโโโโโโโโโโโฌโโโโฎ โ โโ โ โ โ โ โ totalCount โ 1 โ โ โโ โ โ โ โ โฐโโโโโโโโโโโโโดโโโโฏ โ โโ โ โฐโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโฏ โโ 2 โ [list 0 items] โโ 3 โ [list 0 items] โโ 4 โ โญโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโฎ โโ โ โ # โ content โ users โ โโ โ โโโโโผโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโค โโ โ โ 0 โ THUMBS_UP โ โญโโโโโโโโโโโโโฌโโโโฎ โ โโ โ โ โ โ โ totalCount โ 5 โ โ โโ โ โ โ โ โฐโโโโโโโโโโโโโดโโโโฏ โ โโ โ โฐโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโฏ โโฐโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
We care about the total count.
We get that by accessing users.totalCount
.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| insert thumbsUp { $in.reactionGroups | where content == THUMBS_UP | get users.totalCount}| get thumbsUp| first 5
โญโโโโฌโโโโโโโโโโโโโโโโโฎโ 0 โ [list 0 items] โโ 1 โ โญโโโโฌโโโโฎ โโ โ โ 0 โ 1 โ โโ โ โฐโโโโดโโโโฏ โโ 2 โ [list 0 items] โโ 3 โ [list 0 items] โโ 4 โ โญโโโโฌโโโโฎ โโ โ โ 0 โ 5 โ โโ โ โฐโโโโดโโโโฏ โโฐโโโโดโโโโโโโโโโโโโโโโโฏ
Some rows now have empty lists, and some have lists containing a single entry: the number of ๐ reactions.
With get 0
we get the first element of a list.
By adding --optional
, this command doesnโt fail on empty lists but returns null
instead.
We replace null
with 0, by running default 0
.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| insert thumbsUp { $in.reactionGroups | where content == THUMBS_UP | get users.totalCount | get 0 --optional | default 0}| get thumbsUp| first 5
โญโโโโฌโโโโฎโ 0 โ 0 โโ 1 โ 1 โโ 2 โ 0 โโ 3 โ 0 โโ 4 โ 5 โโฐโโโโดโโโโฏ
Get the Five Issues With the Most ๐ Reactions
Section titled โGet the Five Issues With the Most ๐ ReactionsโThe three columns we truly care about are thumbsUp
, title
and url
, so letโs select those.
We also sort the table, so that the issues with the most ๐ reactions come first.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| insert thumbsUp { $in.reactionGroups | where content == THUMBS_UP | get users.totalCount | get 0 --optional | default 0}| select thumbsUp title url| sort-by --reverse thumbsUp| first 5
โญโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโ # โ thumbsUp โ title โ url โโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโคโ 0 โ 5 โ Proposal to allow the use of Pixi workspaces through a named registry of workspaces โ https://github.com/prefix-dev/pixi/issues/4461 โโ 1 โ 1 โ pixi-build: load variants from packages or files โ https://github.com/prefix-dev/pixi/issues/4429 โโ 2 โ 1 โ `pixi run echo '{{ hello }}'` fails โ https://github.com/prefix-dev/pixi/issues/4432 โโ 3 โ 1 โ Environment variable of tasks are broken when defined inside task โ https://github.com/prefix-dev/pixi/issues/4451 โโ 4 โ 1 โ Documentation: Add switchable pyproject.toml / pixi.toml code snippets โ https://github.com/prefix-dev/pixi/issues/4452 โโฐโโโโดโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Rename thumbsUp
Column
Section titled โRename thumbsUp ColumnโUnicode can be a bit annoying to type in the terminal, but now itโs time to rename our thumbsUp
column to ๐.
gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| insert thumbsUp { $in.reactionGroups | where content == THUMBS_UP | get users.totalCount | get 0 --optional | default 0}| select thumbsUp title url| sort-by --reverse thumbsUp| rename --column { thumbsUp: ๐ }| first 5
โญโโโโฌโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโ # โ ๐ โ title โ url โโโโโโผโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโคโ 0 โ 5 โ Proposal to allow the use of Pixi workspaces through a named registry of workspaces โ https://github.com/prefix-dev/pixi/issues/4461 โโ 1 โ 1 โ pixi-build: load variants from packages or files โ https://github.com/prefix-dev/pixi/issues/4429 โโ 2 โ 1 โ `pixi run echo '{{ hello }}'` fails โ https://github.com/prefix-dev/pixi/issues/4432 โโ 3 โ 1 โ Environment variable of tasks are broken when defined inside task โ https://github.com/prefix-dev/pixi/issues/4451 โโ 4 โ 1 โ Documentation: Add switchable pyproject.toml / pixi.toml code snippets โ https://github.com/prefix-dev/pixi/issues/4452 โโฐโโโโดโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Format Table in Markdown Format
Section titled โFormat Table in Markdown FormatโIn the end, we want to add this table to the body of a GitHub issue. Luckily, Nu has integrated support to convert its values to Markdown.
let top_issues_week = gh issue list --repo $repo --json createdAt,reactionGroups,title,url| from json| where ($it.createdAt | into datetime) >= (date now) - 1wk| insert thumbsUp { $in.reactionGroups | where content == THUMBS_UP | get users.totalCount | get 0 --optional | default 0}| select thumbsUp title url| sort-by --reverse thumbsUp| rename --column { thumbsUp: ๐ }| first 5| to md
What you can see here is the Markdown table directly embedded in this post, which is also written in Markdown.
๐ | title | url |
---|---|---|
5 | Proposal to allow the use of Pixi workspaces through a named registry of workspaces | https://github.com/prefix-dev/pixi/issues/4461 |
1 | pixi-build: load variants from packages or files | https://github.com/prefix-dev/pixi/issues/4429 |
1 | pixi run echo '{{ hello }}' fails | https://github.com/prefix-dev/pixi/issues/4432 |
1 | Environment variable of tasks are broken when defined inside task | https://github.com/prefix-dev/pixi/issues/4451 |
1 | Documentation: Add switchable pyproject.toml / pixi.toml code snippets | https://github.com/prefix-dev/pixi/issues/4452 |
Create the Issue
Section titled โCreate the IssueโNow we can create an issue with the table we just generated.
gh issue create --title "Top issues last week" --body $top_issues_week
How to update an existing issue is left as an exercise to the reader.
Conclusion
Section titled โConclusionโI hope I convinced you that scripting with Nushell can be a lot of fun. Itโs quick to type like bash, and has proper data types like Python.
With Nu, itโs easy to interact with your data: you extend your pipeline until you are happy with what it does.
Many thanks to Sabrina and Lucas for their comments and suggestions on this article
You can find the discussion at this Mastodon post.