-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Error redirecting output of a subexspression. This is a bug apparrently... #15416
Description
Describe the bug
I have a script that will (when it's working...) collect statistics on it's activities in a pair of records, then writes these out at the end of the program. The following line writes the "last run record" as JSON to a static file-
$RunRecord | to json o> $RunRecordPath
This works correctly. However I originally wrote it as-
($RunRecord | to json) o> $RunRecordPath (note the parentheses)
This fails to compile with the error-
Error: nu::shell::ir_eval_error
× IR evaluation error: Tried to write to file #0, but it is not open
╭─[/home/username/.../clerk.nu:49:28]
48 │ # Write the run record data
49 │ ($RunRecord | to json) o> $RunRecordPath
· ─┬
· ╰── while running this code
50 │ log ($Stats | to json --raw)
╰────
help: this is a bug, please report it at https://github.com/nushell/nushell/issues/new along with the code you were running if able
So, I am duly reporting the issue.
How to reproduce
The following shows the context in which the error occurs-
let ScriptVersion = '0.0.1'
let RunRecordPath = '/var/log/clerk/lastrun.data'
touch_p $RunRecordPath # initialise run record file
let Interactive: bool = is-fg
let users = real_users
def main [FullScanMode=false] {
let ScanMode = if $FullScanMode {'Full'} else {'Incremental'}
mut Stats = {
'Interactive' : $Interactive
'ScanMode' : $ScanMode
}
mut RunRecord = {
'Interactive' : $Interactive
'ScanMode' : $ScanMode
'RunStart' : (script_start_time | format date "%Y-%m-%d %H:%M:%S")
}
# Write the run record and log data
($RunRecord | to json) o> $RunRecordPath
log ($Stats | to json --raw)
}
# Get the list of real (human) users
def real_users [] {
getent passwd ...(cd /home; ls | get name)
| from csv -n -s ':'
| where column2 > 1000 and column2 < 6500
| get column0
}
# Detect if script has root effective uid. Note the return value
# of id -u is treated as a string by nu
def is-root [] {
if (id -u) == '0' { true } else { false }
}
# Detect if script is in foreground / background
def is-fg [] {
try { tty -s; true } catch { false }
}
# touch (create) a file, also creating any missing intermediate
# directories in the path. Similar to the builtin mkdir
def touch_p [path: string] {
mkdir ($path | path expand | path dirname)
touch ($path | path expand)
}
# Returns start timestamp of the process (as datetime)
def script_start_time [] {
ps -l | where pid == $nu.pid | get start_time.0
}
# Write an entry to the systemd journal
# Retrieve data using "journalctl -t clerk"
def log [msg: string, ident= 'clerk', prio= 'info'] {
echo $msg | systemd-cat -t $ident -p $prio
}
Expected behavior
I expected the parentheses to force execution of the commands (not necessary as it turns out) but otherwise not change the outcome, the output of the parenthesised expression should be the same as the output of the last command in the enclosed pipeline I think (correct?)
Configuration
| key | value |
| ------------------ | ---------------------------------------------------------------- |
| version | 0.103.0 |
| major | 0 |
| minor | 103 |
| patch | 0 |
| branch | makepkg |
| commit_hash | c98642647878b4f66fb7e38388a3973071b0e27b |
| build_os | linux-x86_64 |
| build_target | x86_64-unknown-linux-gnu |
| rust_version | rustc 1.85.1 (4eb161250 2025-03-15) (Arch Linux rust 1:1.85.1-1) |
| cargo_version | cargo 1.85.1 (d73d2caf9 2024-12-31) |
| build_time | 2025-03-21 07:50:32 +00:00 |
| build_rust_channel | release |
| allocator | standard |
| features | default, sqlite, trash |
| installed_plugins | |