Nushell 0.86 | Nushell

19 min read Original article โ†—

Nushell, or Nu for short, is a new shell that takes a modern, structured approach to your command line. It works seamlessly with the data from your filesystem, operating system, and a growing number of file formats to make it easy to build powerful command line pipelines.

Today, we're releasing version 0.86 of Nu. This release adds fish-like directory completions, type system improvements, our first officially supported uutils command, and much more.

Where to get it

Nu 0.86 is available as pre-built binaries or from crates.io. If you have Rust installed you can install it using cargo install nu.

๐Ÿ’ก Note The optional dataframe functionality is available by cargo install nu --features=dataframe.

As part of this release, we also publish a set of optional plugins you can install and use with Nu. To install, use cargo install nu_plugin_<plugin name>.

Table of content

Themes of this release / New features [toc]

Hall of fame [toc]

Bug fixes [toc]

Thanks to all the contributors below for helping us solve issues and bugs ๐Ÿ™. This effort is a major part of what is moving Nushell closer to 1.0 with each release.

authortitlepr
@anka-213Fix exponential parser time on sequence of [[[[#10439
@anka-213Fix tilde-expansion for multi-byte unicode chars#10434
@sholderbachImprove select row perf for large N#10355
@anka-213Prevent cubic time on nested parentheses#10467
@amtoinefix public boolean switches in the standard library#10477
@bobhystd dt datetime-diff: fix uninitialized field ref when borrowing#10466
@NotLebedevFix default argument value type checking#10460
@fdncredfix magenta_reverse and friends#10491
@zhiburtnu-table: Fix failing test (relied on termwidth assumptions)#10492
@sholderbachFix editor config for reedline and config nu/env#10535
@fennewaldFix Default Prompt Tilde Insertion Logic#10539
@sophiajtfix windows default prompt slash direction#10555
@lavafrothfix: complete paths surrounded by quotes or backticks#10600
@dmatos2012ucp: Change error when directory is specified but not recursive#10609
@zhiburtnu-explore: Try to fix a truncation issue in expand view#10580
@kubouchFix wrong parsing of signatures in predecl scan#10637
@kubouchFix parsing of signature inp/out types in predecls#10642
@gaetschwartzfix labelled error from shell error#10639
@CAD97Fix registry query flag validation#10648
@CAD97Fix clippy in registry_query.rs#10652
@WindSoilderfix clippy#10659
@sholderbachFix output types of math commands to be narrower#9740
@zhiburtnu-table: Use config color scheme in kv tables and table -e#10720
@lavafrothfix: only escape path containing numbers if they can be valid floating points#10719
@fdncredevaluate $nu during --ide-check#10470
@WindSoilderallow early return outside of main#10514
@lavafrothPreserve relative paths for local files#10658
@bobhyglob with ../ prefix now works;#10504
@fnuttensAdd support for HTTP proxy in network commands#10401

Enhancing the documentation [toc]

Thanks to all the contributors below for helping us making the documentation of Nushell commands better ๐Ÿ™

authortitlepr
@sholderbachDocstring some intricacies around SyntaxShape#10544
@Hofer-JulianAdd long options for bits and bytes#10601
@Hofer-JulianAdd long options for conversions#10602
@Hofer-JulianUse long options for debug#10621
@Hofer-JulianAdd long options for core and dataframes#10619
@Hofer-JulianAdd long options for filters#10641
@Hofer-JulianAdd long options for formats#10645
@amtoineadd examples with .. and / to path join#10620
@DanyPDevAdd themes to help command when available #10318#10623

Internal changes [toc]

Thanks to all the contributors below for working on the internals of Nushell, doing refactoring and bookkeeping, ... ๐Ÿ™

authortitlepr
@fdncredallow values command to support LazyRecords#10418
@sholderbachRemove dead BSON related tests#10458
@sholderbachSimplify nu! test macros.#10403
@sholderbachImprove assertions in src/tests.rs#10449
@sholderbachSplit up nu-protocol/src/engine/engine_state.rs#10368
@sholderbachRemove unused SyntaxShape::Variable#10511
@sholderbachRemove parsing literals of unrepresentable SyntaxShapes#10512
@amtoinebreak the definition of LS_COLORS onto multiple lines#10538
@sholderbachRename SyntaxShape::Custom to CompleterWrapper#10548
@bobhytoolkit check pr does same clippy checks as github CI#10528
@Hofer-Julianchore: Small refactor of eval.rs#10554
@stormasmengine eval.rs remove pub from fn eval_element_with_input#10587
@sholderbachParse custom completer annotation only in args#10581
@sholderbachMove SyntaxShape specifier parsing into own file#10448
@Hofer-JulianLet run_in_login_mode succeed even with broken local config#10622
@fdncredchange canonicalize test use a more deeply rooted folder#10685
@quat1024Use heck for string casing (again)#10680
@lavafrothrefactor: move the partial_from function to the single place it is invoked#10705

Platform support [toc]

Thanks to all the contributors below for helping Nushell be used on more platforms easily ๐Ÿ™

authortitlepr
@fdncredoptimize aarch64 when able#10433
@hustcerAdd full releases of Nu binaries along with the standard releases#10457
@hustcerfeat: Update nightly build workflow add full release support#10485
@hustcerUpdate winget submission workflow include only default msi files#10487
@hustcerImprove release script for github release workflow#10502
@hustcerUpdate build flags for riscv64gc and armv7 targets#10564

Making errors better [toc]

Thanks to all the contributors below for making errors better and less confusing for users ๐Ÿ™

authortitlepr
@amtoineshow the whole path in "missing mod.nu" errors#10416
@amtoineshow the full directory / file path in "directory not found" error#10430
@WindSoildermake better error message for not operator#10507
@amtoineimprove assertion error messages in std assert#10551
@GPadleyMap DirectoryNotFound to FileNotFound for open command (issue #10085)#10089
@brunerm99Add warning to url join when input key is not supported (#10506)#10565
@amtoinemake "can't follow stream paths" error a bit better#10569
@brunerm99give better error if required field of url join is invalid#10589

Improving the completions in the REPL [toc]

With Nushell 0.86.0 come a few improvements to the completions!

@ZerdoX-x did add built-in support for the doas command in addition to sudo in #10256.

In #10543, @lavafroth have implement Fish-like completions for nested directories. This means that now typing tar/de/inc in the REPL of Nushell and hitting TAB will autocomplete to ./target/debug/incremental if you are in a Rust directory with compiled artifact.

Animation showing shorthand directory expansion

Breaking change

See a full overview of the breaking changes

As a consequence to #10543, @sophiajt helped remove the cd with abbreviation feature from Nushell. This feature will be taken care of by the Fish-like completions described above and the removal mainly means that $env.config.cd.abbreviations is not longer a valid config field: do not forget to update your configs ๐Ÿ˜‰

The type system [toc]

With this new release, we are still working on the type system of Nushell.

@WindSoilder has been working on the arguments and options of custom commands. With #10424, default values won't overwrite type annotations anymore, i.e. the following is now possible:

def foo [x: any = null] { print $"$x" }

foo "string"  # will show `x: string`
foo null      # will show `x: `

Breaking change

See a full overview of the breaking changes

Continuing with the options on custom commands, let's talk about an important change introduced by #10456 about boolean switches:

  • annotating a boolean option will create an option and will require to pass a boolean value
def foo [--option: bool] { if $option { print "yeah" } }

foo --option        # will give an error
foo --option false  # won't print anything
foo --option true   # will print "yeah"
  • to create a boolean switch, you need to omit the type annotation
def bar [--switch] { if $switch { print "yeah" } }

bar           # won't print anything
bar --switch  # will print "yeah"

๐Ÿ’ก Note Boolean options are one step towards addressing a major pain point of Nushell: Passing flags around to other commands. Calling a command with a flag, such as def inner [--foo] { ... }, from another command used to require if-else to pass the flag:

def outer [--foo] {
   if $foo {
       inner --foo
   } else {
       inner
   }
}

With boolean options, it is now possible to define def inner [--foo: bool] { ... } and then call simply as

def outer [--foo] {
   inner --foo $foo
}

Once again, @NotLebedev has been pushing forward type annotations to their limits, this time by allowing complex types in input/output signaturate for custom commands and in let assignments. This means that #10405 allows one to write things like:

let my_r: record<a :int> = { a: 123 }

or

def my_complex_command []: nothing -> record<a: int> { { a: 123 } }

๐Ÿ’ก Note other contributions worth mentioning about the type system:

authortitlepr
@sholderbachUse int type name consistently#10579
@sholderbachRelax type-check of key-less table/record#10629
@fdncredchange Type::Float => SyntaxShape::Number to SyntaxShape::Float#10689

Unified command definitions

Nushell currently has three ways to define a command:

  • def to define a regular command
  • def-env to define a command that preserves the environment
  • extern-wrapped to define a command with a signature where unknown flags and parameters are collected into strings without throwing an error
  • (extern defines an external signature, not a real command)

In this release, @kubouch unified the syntax in #10566 such that the def-env and extern-wrapped are now defined with the --env and --wrapped options to the def keyword. We made this change to go in line with the let-env removal and simplifying the language in general. Also, confusingly, extern-wrapped has nothing to do with extern apart from the permissive signature. We hope the new notation makes it clearer. A bonus feature of this change is that now you can define def --env --wrapped!

๐Ÿ’ก Note In the next release, def-env and extern-wrapped will get deprecated. If you have any of those definitions in your scripts, simply replace them with def --env or def --wrapped. In the following releases, they will be removed completely.

Some news with the standard library [toc]

Thanks to @Yethal and their work in #10545, the use of the test runner and the std testing run-tests command should be faster!

Work has been done to improve the std log module:

Finally, a bug with std dirs goto, a shell command in the prelude of the library, has been fixed by @bobhy in #10706.

Miscellaneous [toc]

Nushell now supports the keyboard enhancement protocol from Kitty with the work of @Abdillah in #10540. This feature is off by default but can be turned on in config.nu with the $env.use_kitty_protocol config option.

Nushell and Direnv are now integrated with each other thanks to @amtoine in direnv/direnv#1175 and #10675.

With the changes from #10593 written by @gaetschwartz, open can now read tar.gz file because from can handle multiple extensions. To be more precise, if from tar.gz and from gz are defined at the same time, open foo.tar.gz will try to call from tar.gz first and then fall back to from gz.

Let's finish with some delight to make the Nushell experience a bit nicer:

Our set of commands is evolving [toc]

As usual, new release rhyms with changes to commands!

It's official! ๐Ÿฅณ With the landing of PR 10678 the uutils/coreutils version of cp is now the default copy command in nushell. We're so happy to have this command landed and we're working on several other commands. If you'd like to help out please visit our Discord and ask about helping. The coreutils team would also appreciate your help since changes need to be made there before integrating into nushell.

New commands [toc]

  • when parsing raw data streams from external commands, a common task in Nushell is to give explicit types to all fields and columns of the parsed data structure. Until now, this had to be done manually but, thanks to @fdncred and #10427, the new into value command should help make that task easier by trying to infer the types for you:
# should help you catch integer user and group IDs in the `/etc/passwd` file on *nix systems
open /etc/passwd | lines | split column ":" user . uid gid desc home shell | into value
  • @zhiburt did add an --abbreviated option to table to truncate the output of long tables in #10399
  • to get the content of the default config files of Nushell without overwriting the true config.nu and env.nu, @poliorcetics have added the --default option to both config nu and config env in #10480
  • to know about all the available escapes that Nushell supports, @vedaRadev have added help escapes in #10522
  • tired of crawling the internet or computing series of number with loops and mutable variables? @hudclark got your back with the new unfold command from #10489! The first 10 Fibonacci numbers can now be computed very easily with something like
unfold [0, 1] {|fib| {out: $fib.0, next: [$fib.1, ($fib.0 + $fib.1)]} } | first 10

To crawl multi-page API responses, e.g. when listing issues of a GitHub repository, the unfold is very handy and allows to transform

mut pages = []
for page in 1.. {
  let resp = http get (
    {
      scheme: https,
      host: "api.github.com",
      path: "/repos/nushell/nushell/issues",
      params: { page: $page, per_page: $PAGE_SIZE }
    } | url join)

  $pages = ($pages | append $resp)

  if ($resp | length) < $PAGE_SIZE {
    break
  }
}
$pages

into

unfold 1 {|page|
  let resp = http get (
    {
      scheme: https,
      host: "api.github.com",
      path: "/repos/nushell/nushell/issues",
      params: { page: $page, per_page: $PAGE_SIZE }
    } | url join)

  if ($resp | length) < $PAGE_SIZE {
    {out: $resp}
  } else {
    {out: $resp, next: ($page + 1)}
  }
}
  • in previous release, from ndjson and from jsonl have been added to the standard library. In this new release, @amtoine has added their to counterpart in #10519
  • to complete url encode, url decode has been added by @lpchaim in #10611
  • dfr to get some help on dataframes by @sholderbach in #10683
  • our mascot ellie has been added to the standard library by @amtoine in #10686
  • complementary to the sys command, debug info, added by @fdncred in #10711, should give more insight into the resources Nushell is using at runtime

Changes to existing commands [toc]

The open command is now case-insensitive when it comes to file extensiens thanks to @poketch in #10451.

A bug inside from ics and from vcf has been fixed thanks to @joergsch in #10577.

Breaking change

See a full overview of the breaking changes

With #10526 from @WindSoilder, the --column option of the rename command now takes a record instead of a list:

> ls | where type == file | rename --column {name: filename, size: nb_bytes}
#โ”ฌfilenameโ”€โ”ฌtypeโ”ฌnb_bytesโ”ฌโ”€โ”€โ”€โ”€โ”€modifiedโ”€โ”€โ”€โ”€โ”€โ”€
0โ”‚LICENSE  โ”‚fileโ”‚ 35.1 KBโ”‚2022-12-23 11:34:42
1โ”‚README.mdโ”‚fileโ”‚  9.3 KBโ”‚2023-10-04 18:41:25
โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

The do command can now mutate its outside environment with a new --env option added by @ClipplerBlood in #10572. This means that the following will now be possible:

do --env { cd some/where }

A few updates on the explore command [toc]

Once again, @rgwood has done work to simplify the explore command

  • the highlighting of selected cells has been made easier to see in #10533 |
  • some config options have been removed in#10559, #10562 and #10570

Deprecated commands [toc]

The following commands and options are being deprecated and will be removed soon:

  • random int in favor of random integer in #10520
  • the $nothing built-in variable in favor of the null value in #10478
  • to xml --pretty {int} in favor of to xml --indent {int} in #10660

Removed commands [toc]

The following commands are being removed from Nushell:

  • random decimal in favor of random float in #10342
  • into decimal in favor of into float in #10341

Breaking changes [toc]

  • #10456 differentiating between --x and --x: bool

In 0.86, we now differentiate between a switch --x and a flag with a boolean argument --x: bool. If you declare a flag as a parameter and give it the : bool type annotation, we now require that the flag is followed by a boolean value. Previously, we took the boolean type to mean that the flag was actually a switch.

  • #10680 Use heck for string casing (again)

Before

> [UserID ABCdefGHI foo123bar] | str camel-case
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ 0 โ”‚ userID    โ”‚
โ”‚ 1 โ”‚ abcdefGHI โ”‚
โ”‚ 2 โ”‚ foo123Bar โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> [UserID ABCdefGHI foo123bar] | str snake-case
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ 0 โ”‚ user_id     โ”‚
โ”‚ 1 โ”‚ ab_cdef_ghi โ”‚
โ”‚ 2 โ”‚ foo_12_3bar โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

After

> [UserID ABCdefGHI foo123bar] | str camel-case
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ 0 โ”‚ userId    โ”‚
โ”‚ 1 โ”‚ abCdefGhi โ”‚
โ”‚ 2 โ”‚ foo123bar โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> [UserID ABCdefGHI foo123bar] | str snake-case
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ 0 โ”‚ user_id     โ”‚
โ”‚ 1 โ”‚ ab_cdef_ghi โ”‚
โ”‚ 2 โ”‚ foo123bar   โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

cd with abbreviations was a feature you could enable to expand an abbreviated path for you automatically. It would do so after you hit return. In comparing the experience between this and the fish-like path abbreviation completions added in 0.86, we decided the new style of completions satisfied this in a much more visual way.

  • #10526 Rename: change the SyntaxShape of -c flag from list to record

After this change, we need to use -c flag like this:

> [[a, b, c]; [1, 2, 3]] | rename -c { a: ham }
But we can rename many columns easily, here is another example:
> [[a, b, c]; [1, 2, 3]] | rename -c { a: ham, b: ham2 }

Full changelog [toc]

Nushell

Extension

Documentation

Nu_Scripts

Reedline