nushell icon indicating copy to clipboard operation
nushell copied to clipboard

unhelpful "variable not found" error when using `$it` in a closure

Open amtoine opened this issue 2 years ago • 1 comments

Describe the bug

i was trying to ls each file and directory given by ls in the current directory, and reusing the it variable of the each closure to print more useful stuff but i get a very strange and unhelpful variable_not_found error :thinking:

let me simplify the code to the bare minimum i could find to reproduce the error.

Important DISCLAIMER: not sure i get what's happening at all here :open_mouth:

How to reproduce

Note it appears to give the error below regardless of the directory, you can for instance go to your local fork of Nushell, i see the error there at least!

  1. run the following
ls . | each {|it|
    ls $it.name | where type == "file" | each {|| print $it.name }
} | ignore
  1. observe the unhelpful error
Error: nu::shell::variable_not_found

  × Variable not found
   ╭─[entry #187:1:1]
 1 │ ╭─▶ ls . | each {|it|
 2 │ │       ls $it.name | where type == "file" | each {|| print $it.name }
 3 │ ├─▶ } | ignore
   · ╰──── variable not found
   ╰────

Expected behavior

i expected the above to print each name in the current directory but duplicated when it's a directory, with the same number of prints as there are items in the directory, but only files, e.g.

  • README.md, LICENSE and toolkit.nu are files and thus are printed once
  • crates/ contains 30 subdirectories but only 1 file and thus is printed 1 time
  • scripts/ contains exactly 12 files and thus is printed 12 times
  • ...

Screenshots

No response

Configuration

key value
version 0.84.1
branch main
commit_hash f8939de14fd5d74fa35299cb95e5c09ce016d05c
build_os linux-x86_64
build_target x86_64-unknown-linux-gnu
rust_version rustc 1.70.0 (90c541806 2023-05-31)
rust_channel 1.70.0-x86_64-unknown-linux-gnu
cargo_version cargo 1.70.0 (ec8a8a0ca 2023-04-25)
build_time 2023-09-19 18:39:26 +02:00
build_rust_channel release
allocator mimalloc
features default, sqlite, trash, which, zip
installed_plugins gstat, nu_plugin_explore

Additional context

alternatives that do solve this

remove the where

ls . | each {|it|
    ls $it.name | each {|| print $it.name }
} | ignore

gives

LICENSE
README.md
...

do not print $it.name

ls . | each {|it|
    ls $it.name | where type == "file" | each {|| print "foo" }
} | ignore

gives

foo
foo
...

do not use it as the outer each variable name

ls . | each {|foo|
    ls $foo.name | where type == "file" | each {|| print $foo.name }
} | ignore

gives the expected result

LICENSE
README.md
...

amtoine avatar Sep 19 '23 16:09 amtoine

DISCLAIMER: not sure i get what's happening at all here 😮

To me it looks like $it (introduced by where) is not properly cleaned up (restoring its to the state it was in before) when its pipe element ends, but instead is fully removed from the scope and then print $it.name triggers unknown variable error.

weirdan avatar Aug 16 '24 21:08 weirdan