Skip to main content

Notable Changes

Commandsโ€‹

In Nushell, several traditional commands have lost their original meaning or have been replaced by more modern and structured approaches. Some notable examples include:

  • awk: Nushell offers native functionality for structured data manipulation, making awk largely unnecessary.
  • sed: Like awk, many of sed's functions are replaced by Nushell's internal commands for string and data manipulation.
  • grep: Nushell has native commands for data filtering and searching, reducing the need for traditional grep.
  • find: Nushell implements its own file search version, which is more integrated with the structured data manipulation system.
  • wc: Functions like line counting are performed differently in Nushell, using pipelines and native commands.
  • jq and yq: With Nushell treating JSON and YAML data natively, tools like jq become less necessary.

These traditional commands like sed, grep, awk, and others still exist in Nushell, but for different reasons than in traditional shells: Nushell maintains these commands to ensure compatibility with existing scripts and workflows, gradual transition, interoperability, etc.

Flagsโ€‹

When migrating to Nushell, one of the most striking differences is the new approach regarding commands and their flags. Users familiar with shells like Bash or Zsh may initially find the absence of traditional flags in many well-known commands strange. This change reflects Nushell's core philosophy: treat data in a structured way and offer a more simplified command syntax.

In Nushell, many commands have been redesigned to operate without flags, adopting a subcommand and pipeline-based approach. This new structure promotes the use of pipelines to filter and manipulate data, replacing traditional flags with a series of interconnected commands. This methodology, although initially different, provides a more intuitive and flexible way to interact with the system and process information.

However, as mentioned previously, the help documentation for commands is very well done, facilitating this migration.

An example would be the ps aux command that we use to see processes, which practically lost all its flags, with only -l remaining to view all columns.

~/test> ps -h
View information about system processes.

Search terms: procedures, operations, tasks, ops

Usage:
> ps {flags}

Flags:
-h, --help: Display the help message for this command
-l, --long: list all available columns for each entry

Input/output types:
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ # โ”‚ input โ”‚ output โ”‚
โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0 โ”‚ nothing โ”‚ table โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Examples:
List the system processes
> ps

List the top 5 system processes with the highest memory usage
> ps | sort-by mem | last 5

List the top 3 system processes with the highest CPU usage
> ps | sort-by cpu | last 3

List the system processes with 'nu' in their names
> ps | where name =~ 'nu'

Get the parent process id of the current nu process
> ps | where pid == $nu.pid | get ppid

It's possible to execute a command through nushell as implemented by the operating system instead of using the redesigned command.

The ls -lha command doesn't exist in nushell because the -h flag no longer exists. But if we want to invoke the native ls from the system we can use ห† in front of the command. You'll see that the data returns to text form and is no longer structured.

# This searches for ls directly from /bin/ls
~/test> ^ls -lha
total 48
drwxr-xr-x@ 5 davidprata staff 160B 11 Feb 06:51 .
drwxr-x---+ 70 davidprata staff 2.2K 11 Feb 08:32 ..
-rw-r--r--@ 1 davidprata staff 15K 13 Jan 14:31 pod.yaml
-rwxr-xr-x@ 1 davidprata staff 400B 11 Feb 06:51 script.sh

The commands inside Nushell are not traditional operating system binaries, but rather an internal implementation of Nushell itself. This implementation is part of Nushell's source code and is compiled together with the shell.

Errorsโ€‹

The way Nushell handles errors is a show in itself! Error messages are presented in a clear, concise, and highly informative manner.

  • Simplicity: Errors are displayed directly, without unnecessary technical jargon.
  • Ease of understanding: Messages are formulated in accessible language, facilitating quick understanding of the problem.
  • Useful suggestions: In many cases, Nushell goes beyond simple error notification, offering practical suggestions for resolution.
  • Contextualization: Errors are frequently accompanied by relevant contextual information, helping to identify the origin of the problem.
  • Visual formatting: The visual presentation of errors is well structured, using colors and formatting to highlight important information.

This intuitive approach to error handling seems to anticipate user needs, making the debugging and problem-solving process significantly more efficient and less frustrating.

~> open deploy.yaml | get spec.template.spec.container
Error: nu::shell::name_not_found

ร— Name not found
โ•ญโ”€[entry #8:1:43]
1 โ”‚ open deploy.yaml | get spec.template.spec.container
ยท โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€
ยท โ•ฐโ”€โ”€ did you mean 'containers'?
โ•ฐโ”€โ”€โ”€โ”€
~> open deploy.yaml | get spec.template.spec.containers
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ # โ”‚ image โ”‚ name โ”‚ resources โ”‚
โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0 โ”‚ nginx โ”‚ nginx โ”‚ {record 0 fields} โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
# -p doesn't exist...
~> ls -lp
Error: nu::parser::unknown_flag

ร— The `ls` command doesn't have flag `-p`.
โ•ญโ”€[entry #9:1:6]
1 โ”‚ ls -lp
ยท โ”ฌ
ยท โ•ฐโ”€โ”€ unknown flag
โ•ฐโ”€โ”€โ”€โ”€
help: Available flags: --help(-h), --all(-a), --long(-l), --short-names(-s), --full-paths(-f), --du(-d), --directory(-D),
--mime-type(-m), --threads(-t). Use `--help` for more information.
~> echo $LANG
Error: nu::parser::env_var_not_var

ร— Use $env.LANG instead of $LANG.
โ•ญโ”€[entry #30:1:6]
1 โ”‚ echo $LANG
ยท โ”€โ”€โ”ฌโ”€โ”€
ยท โ•ฐโ”€โ”€ use $env.LANG instead of $LANG
โ•ฐโ”€โ”€โ”€โ”€

~> echo $env.LANG
pt_BR.UTF-8

Environment Variablesโ€‹

In Nushell, the env command is an external system command, not specific to Nushell, which is why:

  • It shows environment variables in the traditional key=value format.
  • The output is plain text, not structured.

The $env command is an internal Nushell command.

  • It shows environment variables as a data structure.
  • The output is structured, typically in table format.

The difference reflects Nushell's philosophy of treating data in a structured way. When you use $env, you're directly accessing Nushell's environment object, which maintains variables in a richer and more manipulable format.

In most cases, $env in Nushell and the traditional env command will show the same environment variables with the same values. However, there may be some differences:

  • $env in Nushell generally includes all variables shown by traditional env.
  • $env may contain additional Nushell-specific variables that don't appear in traditional env.
  • Some variables may be presented differently in $env. For example, PATH may be shown as a list in Nushell, while in traditional env it's a colon-separated string.
  • Nushell may add or modify some environment variables during initialization.

Just to compare quickly...

~> env | wc -l
56
# It's necessary to format the $env output to have everything divided into lines and columns.
~> $env | transpose key value | length
62

We can observe that we have more, but the 56 we found are within the 62.

Nushell inherits environment variables from the parent process that started it.

This approach offers several advantages:

  • Organization: All environment variables are grouped in a single location, facilitating management.
  • Clarity: The $env. prefix makes it explicit that you're dealing with an environment variable, not a local or global variable.
  • Structure: $env is treated as a structured object, allowing more advanced and consistent operations.
  • Typing: Variables within $env can maintain their original data types, not being limited to just strings.
  • Safety: This structure helps prevent accidental conflicts with other variables in the shell.

Environment variables and Nushell-specific settings are stored in the $env object. General environment variables are accessed directly through $env, while Nushell settings are maintained in $env.config. We'll explore $env.config in more detail when we address advanced Nushell optimization and customization, allowing us to take full advantage of it.

The $env object encompasses not only standard environment variables, but also Nushell-specific settings and other internal variables. This explains why $env shows 62 entries, while the env command shows only 56.

The path variable that was previously separated by : now has a structure that shows each path as an item.

~/test> $env.PATH

# We'll talk about this later.
~/test> $env.config
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ filesize โ”‚ {record 2 fields} โ”‚
โ”‚ table โ”‚ {record 8 fields} โ”‚
โ”‚ ls โ”‚ {record 2 fields} โ”‚
โ”‚ color_config โ”‚ {record 59 fields} โ”‚
โ”‚ footer_mode โ”‚ 25 โ”‚
โ”‚ float_precision โ”‚ 2 โ”‚
โ”‚ recursion_limit โ”‚ 50 โ”‚
โ”‚ use_ansi_coloring โ”‚ true โ”‚
โ”‚ completions โ”‚ {record 7 fields} โ”‚
โ”‚ edit_mode โ”‚ emacs โ”‚
โ”‚ history โ”‚ {record 4 fields} โ”‚
โ”‚ keybindings โ”‚ [list 0 items] โ”‚
โ”‚ menus โ”‚ [list 0 items] โ”‚
โ”‚ hooks โ”‚ {record 5 fields} โ”‚
โ”‚ rm โ”‚ {record 1 field} โ”‚
โ”‚ shell_integration โ”‚ {record 7 fields} โ”‚
โ”‚ buffer_editor โ”‚ vim โ”‚
โ”‚ show_banner โ”‚ false โ”‚
โ”‚ bracketed_paste โ”‚ true โ”‚
โ”‚ render_right_prompt_on_last_line โ”‚ false โ”‚
โ”‚ explore โ”‚ {record 0 fields} โ”‚
โ”‚ cursor_shape โ”‚ {record 3 fields} โ”‚
โ”‚ datetime_format โ”‚ {record 2 fields} โ”‚
โ”‚ error_style โ”‚ fancy โ”‚
โ”‚ display_errors โ”‚ {record 2 fields} โ”‚
โ”‚ use_kitty_protocol โ”‚ false โ”‚
โ”‚ highlight_resolved_externals โ”‚ false โ”‚
โ”‚ plugins โ”‚ {record 0 fields} โ”‚
โ”‚ plugin_gc โ”‚ {record 2 fields} โ”‚

Some Conveniencesโ€‹

mkdir now has -p automatically

mkdir test1/test2/test3
tree test1/
test1/
โ””โ”€โ”€ test2
โ””โ”€โ”€ test3

No need to type cd to change folders. Type the path and it goes directly.

> pwd
/home/david/test
> test1/
> pwd
/home/david/test/test1
>..
>pwd
/home/david/test

Some Differencesโ€‹

The > to redirect output somewhere doesn't work.

# This doesn't work
> echo "david" > file.txt
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ 0 โ”‚ david โ”‚
โ”‚ 1 โ”‚ > โ”‚
โ”‚ 2 โ”‚ file.txt โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

# file.txt was not even created
> ls
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ # โ”‚ name โ”‚ type โ”‚ size โ”‚ modified โ”‚
โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0 โ”‚ test3 โ”‚ dir โ”‚ 64 B โ”‚ 10 minutes ago โ”‚
โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

If you want to do this, let's use save.

>echo "david" | save file.txt
> ls
โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ # โ”‚ name โ”‚ type โ”‚ size โ”‚ modified โ”‚
โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0 โ”‚ file.txt โ”‚ file โ”‚ 5 B โ”‚ now โ”‚
โ”‚ 1 โ”‚ test3 โ”‚ dir โ”‚ 64 B โ”‚ 11 minutes ago โ”‚

But why doesn't this work? It's trying to compare things

4 > 10
false

Some things seem the same but are different. While a echo "Hello my friend" command is throwing the value to output, nushell is returning from a command, so we can do this.

"Hello my friend" == (echo "Hello my friend")
true

Even though it's showing, it's actually showing the function return and this won't go to the console, so using echo in a nu script thinking it will print to the console doesn't work. If you want this, we need to use print.

print "Hello my friend"
Hello my friend

Background tasks like in bash for example my_long_command & are not yet supported by nushell. There are solutions using Pueue, take a look later, but I practically don't use it in my daily work. When I need something like this, I simply open another terminal. My intention is to use Nushell for productivity.

We'll learn these things over time.

It's worth noting some differences with bash.

Over time, using the documentation better, we'll learn more. For now, I believe this is enough to help us adapt to Nushell.