This is a configuration for nushell, a pipeline-oriented shell with top-notch data manipulation, support for data structures for shell IO, and excellent scripting capabilities.
I use nushell
as my default login shell, although this style is a modicum of
additional work to setup and completely disregards POSIX compliancy. If these
features are important to your setup working with command-line shells, nushell
can still be used ad-hoc or without being a login shell.
We are living in the golden-era of alternative shells (among other things).
Besides the standard sh
, bash
, zsh
, and fish
options that most UNIX
users are exposed to, I can think of several additional shells off the top of my
head: dash
, xonsh
, elvish
, oil
, ion
, and the list goes
on...
nushell
, situated against the rest of the pack, offers a few positives.
nushell
has excellent support for pipelines. The syntax is clean and easy to
use, as in the following example, which sets up direnv
at the appropriate time
during shell init:
direnv export json | from json | default {} | load-env
or equivalently given:
(
direnv export json
| from json
| default {}
| load-env
)
It is also straightforward to debug or otherwise inspect pipelines as there are a number of commands for such introspections that come out of the box:
(
direnv export json
| from json
| default {}
| inspect
| load-env
)
Other nice introspection commands include: describe
, explain
, and
metadata
; a complete list is available via nushell's command
reference
nushell
is also pleasant to work with as it generally supports data structures
in various forms as command and pipeline input/output values, and does not rely
on any sort of conversion of data types unless you are sending or receiving from
an external (i.e. non-nushell) program (in this case conversion is required
simply because the external doesn't know what to do with non-string values)
The support for stronger typing means that custom commands have a broader ability to self-document and provide nice language features that come with such typing. As such, I find it more efficient and cleaner to script in nushell than other shells.
Examine, for instance, the following custom command definition for a
coalesce
implementation:
def coalesce [
...args: any
--predicate: closure
]: [nothing -> any list<any> -> any] {
# store pipeline input
let pipein = $in
# put pipeline input before passed positional args, if any
let fullargs = ($pipein | default [])
| append ($args | default [])
# filter the given arguments by the optional predicate closure
let testargs = (
if $predicate != null {
$fullargs | filter $predicate
} else {
$fullargs
}
)
# exclude null elements
let found = $testargs | filter {|it| $it != null }
# get first non-null
$found | first
}
With this definition, when this command is invoked, it will check the data types
for positional arguments (e.g. ...args
), flags (e.g. --predicate
), and
pipeline inputs (e.g. data sent into the coalesce
command via |
), and will
fail with a descriptive error in cases where the expected types are not
received.
The nushell
community is generally quite helpful, friendly, and larger than
some of the other shell options. There have been several versions of nushell
released throughout the years, and there is lots of active development
happening; this seems coordinated mostly through nushell
's discord channel.
This configuration is relatively straightforward, but offers the ability to
extend with customizations that are modular and composable. It does so by using
nushell
's autoload directories. This provides a convenient way to include both
vendor-provided implementations for integrating with nushell
(e.g.
starship
, zoxide
) as well as user provided customizations which are
ultimately evaluated via extension binning that is present in the
user-autoload directory (e.g. the autoload
subdirectory of the nushell
configuration directory). The rough directory structure is as follows:
aliases
: represents simple command aliasesexternal
: represents simple wrappers around external commands that are used frequentlyhooks
: (not sourced via autoload) represents stub implementations for certain behaviors that occur if aware ofnushell
's hooksoverlays
: contains moudles that are designed to be used as overlays, which is to say in a more ad-hoc fashion.ustd
: the user std lib; contains core ubiquitous command implementations of the user's design. Not to be confused with thenushell
builtinstd
moduleutils
: a hodgepodge bin of commands that are maybe used in some places but don't qualify forustd
; also include WIP candidates forustd
If you want to use this configuration or otherwise contribute here, note that I
am experimenting with the use of jj
as a git alternative, so far to promising
results. I don't know exactly if you will also need jj
to work with this repo,
but I'm guessing not.