[Short Tip] Output/redirect content to a file in Nushell

And another short tip about Nushell – I promise that those will be less frequent the more I get used to it.

My current problem was: how do I redirect content to a file like echo hello > foo.txt and echo world >> foo.txt? The typical approach didn’t work:

❯ echo "hello" > foo.txt
───┬─────────
 0 │ hello   
 1 │ >       
 2 │ foo.txt 
───┴─────────

Yeah, certainly not what I had in mind. Instead, I had to rethink the approach here. What is what we want to do here? First we output content and need to save it to a file. The connection is a pipe, as usual in Nushell:

❯ echo hello | save foo.txt
❯ open foo.txt
hello

That worked! Second, we want to append something. So we need to open the file, append something, and save it again. In between all steps we need pipes – Nushell, after all:

❯ open foo.txt | append "world"| save --raw foo.txt
❯ open foo.txt
hello
world

Note that save needs the --raw flag here: it tries to be smart to guess in what format we want to save it, and for some reason in my case it didn’t save the new lines without the flag.

And that’s it. It is not as short as I would like it to be compared to Bash and others. On the other hand it is way more flexible (it can also handle structured data this way like json) and it is not like I use redirection all the time.

[Short Tip] Executing a subshell in Nushell

I just run through a howto where I was asked to execute a command which used the command output from a subshell as an argument for another command. Copy&paste of such typical command examples don’t work with nushell:

❯ sudo usermod --append --groups libvirt $(whoami)
error: Variable not in scope
  ┌─ shell:9:40
  │
9 │ sudo usermod --append --groups libvirt $(whoami)
  │                                        ^^^^^^^^^ unknown variable: $(whoami)

The right way to do that in nushell is only slightly different – using subexpressions:

❯ sudo usermod --append --groups libvirt (whoami)

[Short Tip] Get data type in Nushell

Nushell supports multiple data types. If you get lost what exact data type you are working with just right now, the describe command can help:

❯ echo 1 | describe
integer

❯ echo "1" | describe
string

Unfortunately right now it does not support structured data types like “list” or “table”. Hopefully that will be added in the future:

❯ echo [a b c] | describe
───┬─────────────────────
 0 │ string 
 1 │ string 
 2 │ string 
───┴─────────────────────

Image by BRRT from Pixabay

[Short Tip] Doing for-loops in Nushell

Nushell 0.32 added support for typical for loops:

With the new for..in command, you can write more natural iterating loops:

Nushell 0.32 release notes
> for $x in 1..3 { echo ($x + 10) }
───┬────
 0 │ 11 
 1 │ 12 
 2 │ 13 
───┴────

Compared to what we have in Bash and others (and given my limited understanding) the most notable difference is that there is no “do”, but instead a curly bracket defining what should be done.

Also, remember that Nushell has an understanding of various data types, so the iterator in the example above is indeed of type “int”. Just stitching it together with another string doesn’t work:

❯ for $i in 1..3 {echo ("/home/" + $i) }
error: Coercion error
   ┌─ shell:31:23
   │
31 │ for $i in 1..3 {echo ("/home/" + $i) }
   │                       ^^^^^^^^   -- integer
   │                       │           
   │                       string

Instead, make sure to echo the iterator:

❯ for $i in 1..3 {echo $"/home/(echo $i)" }
───┬─────────
 0 │ /home/1 
 1 │ /home/2 
 2 │ /home/3 
───┴─────────

For comparison, if you have a set of strings you can provide them in a table and stitch them together easily:

❯ for $i in [a b c d] {echo ("/home/" + $i) }
───┬─────────
 0 │ /home/a 
 1 │ /home/b 
 2 │ /home/c 
 3 │ /home/d 
───┴─────────

[Short Tip] Access system variables in Nushell

Working with variables in Nushell works mostly like you would expect it. If you want to define a variable, you need the keyword let:

❯ let my_variable = "hello blog readers"

❯ echo $my_variable
hello blog readers

Note that you need the spaces around the equal sign character!

❯ let my_variable="hello blog readers"
error: let requires the equals sign parameter
   ┌─ shell:21:1
   │
21 │ let my_variable="hello blog readers"
   │ ^^^ requires the equals sign parameter

But apart from defining your own variables, there is a surprised when you try to access typical system variables:

❯ echo $HOME
error: Variable not in scope
   ┌─ shell:25:6
   │
25 │ echo $HOME
   │      ^^^^^ unknown variable: $HOME

The reason for that error is that Nushell places system environment variables underneath the main variable $nu:

❯ echo $nu|pivot
───┬─────────────────┬────────────────────────────────────────────
 # │     Column0     │                  Column1                   
───┼─────────────────┼────────────────────────────────────────────
 0 │ env             │ [row 34 columns]                           
 1 │ history-path    │ /home/liquidat/.local/share/nu/history.txt 
 2 │ config          │ [row path prompt startup]                  
 3 │ config-path     │ /home/liquidat/.config/nu/config.toml      
 4 │ path            │ [table 5 rows]                             
 5 │ cwd             │ /home/liquidat
 6 │ home-dir        │ /home/liquidat
 7 │ temp-dir        │ /tmp                                       
 8 │ keybinding-path │ /home/liquidat/.config/nu/keybindings.yml  
───┴─────────────────┴────────────────────────────────────────────

❯ echo $nu.env|pivot
────┬──────────────────────────┬────────────────────────────────────────────────────
 #  │         Column0          │                      Column1                       
────┼──────────────────────────┼────────────────────────────────────────────────────
  0 │ CMD_DURATION_MS          │ 2                                                  
  1 │ HOME                     │ /home/liquidat                                            
  2 │ SYSTEMD_EXEC_PID         │ 2958                                               
  3 │ SSH_AUTH_SOCK            │ /run/user/1000/keyring/ssh                         
  4 │ SESSION_MANAGER          │ local/unix:@/tmp/.ICE-unix/2557,unix/unix:/tmp/.IC 
    │                          │ E-unix/2557                                        
  5 │ GNOME_TERMINAL_SCREEN    │ /org/gnome/Terminal/screen/71e37281_4af2_4c9b_be19 
[...]

❯ echo $nu.env.HOME
/home/liquidat

The environment variables are generated from the environment Nushell was started in. If you need to update those for the current environment, use the command let-env:

❯ echo $nu.env.LANG
en_US.UTF-8

❯ let-env LANG = C

❯ echo $nu.env.LANG
C

Image by Susanne Westphal from Pixabay