unhelpful "variable not found" error when using `$it` in a closure
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!
- run the following
ls . | each {|it|
ls $it.name | where type == "file" | each {|| print $it.name }
} | ignore
- 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,LICENSEandtoolkit.nuare 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
...
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.