Background Jobs
Nushell currently has experimental support for thread-based background jobs.
Spawning Jobs
Jobs can be spawned using job spawn, which receives a closure and starts its execution in a background thread, returning a unique integer id for the spawned job:
'i am' | save status.txt
job spawn { sleep 10sec; ' inevitable' | save --append status.txt }
# => 1
open status.txt
# => i am
# wait for 10 seconds
sleep 10sec
open status.txt
# => i am inevitableListing and Killing jobs
Active jobs can be queried with the job list command, which returns a table with the information of the jobs which are currently executing. Jobs can also be killed/interrupted by using the job kill command, which interrupts the job's thread and kills all of the job's child processes:
let id = job spawn { sleep 1day }
job list
# => ╭───┬────┬────────┬────────────────╮
# => │ # │ id │ type │ pids │
# => ├───┼────┼────────┼────────────────┤
# => │ 0 │ 2 │ thread │ [list 0 items] │
# => ╰───┴────┴────────┴────────────────╯
job kill $id
job list
# => ╭────────────╮
# => │ empty list │
# => ╰────────────╯Describing jobs
To make jobs easier to tell apart, you can give a job a description when you spawn it with job spawn --description, or change it later with job describe. The description is shown in an additional description column of job list:
let id = job spawn --description "long nap" { sleep 1day }
job describe $id "longer nap"
job list
# => ╭───┬────┬────────┬────────────────┬─────────────╮
# => │ # │ id │ type │ pids │ description │
# => ├───┼────┼────────┼────────────────┼─────────────┤
# => │ 0 │ 3 │ thread │ [list 0 items] │ longer nap │
# => ╰───┴────┴────────┴────────────────┴─────────────╯
job kill $idJob suspension
On Unix targets, such as Linux and macOS, Nushell also supports suspending external commands using Ctrl+Z. When a running process is suspended, it is turned into a "frozen" background job:
^sleep 100 # this starts running, then Ctrl+Z is pressed
# => Job 4 is frozen
job list
# => ╭───┬────┬────────┬──────────────┬─────────────╮
# => │ # │ id │ type │ pids │ description │
# => ├───┼────┼────────┼──────────────┼─────────────┤
# => │ 0 │ 4 │ frozen │ ╭───┬──────╮ │ sleep │
# => │ │ │ │ │ 0 │ 6337 │ │ │
# => │ │ │ │ ╰───┴──────╯ │ │
# => ╰───┴────┴────────┴──────────────┴─────────────╯A frozen job is automatically described with the name of the suspended program.
A frozen job can be brought back into foreground with the job unfreeze command:
job unfreeze
# process is brought back where it stoppedTip
For those familiar with other Unix shells, you can create an alias to emulate the behavior of the fg command:
alias fg = job unfreezeBy default, job unfreeze will unfreeze the most recently frozen job. However, you can also specify the id of a specific job to unfreeze:
vim
# => Job 5 is frozen
^sleep 100
# => Job 6 is frozen
job unfreeze 5
# we're back in vimCommunicating between jobs
Data can be sent to a job using job send <id>, and the job can receive it using job recv:
let jobId = job spawn {
job recv | save sent.txt
}
'hello from the main thread' | job send $jobId
sleep 1sec
open sent.txt
# => hello from the main threadThe main thread has a job ID of 0, so you can also send data in the other direction:
job spawn {
sleep 1sec
'Hello from a background job' | job send 0
}
job recv
# => Hello from a background jobMessages can carry a numeric tag with job send --tag. job recv --tag then only receives messages with that tag, leaving others in the mailbox, and job recv --timeout stops waiting after the given duration:
'low priority' | job send 0 --tag 2
'urgent' | job send 0 --tag 1
job recv --tag 1
# => urgent
job recv --timeout 0sec
# => low priorityTo discard messages without reading them, use job flush, which clears the whole mailbox of the current job, or only the messages with a given tag when used with --tag.
Exit Behavior
Unlike many other shells, Nushell jobs are not separate processes, and are instead implemented as background threads.
An important side effect of this, is that all background jobs will terminate once the shell process exits. For this reason, Nushell has no UNIX-like disown command to prevent jobs from terminating once the shell exits. To account for that, there are plans for a job dispatch implementation in the future, for spawning independent background processes (see #15201 for progress).
Additionally, if the user is running an interactive Nushell session and runs exit while there are background jobs running, the shell will warn about them before prompting the user to confirm exit.
Pressing Ctrl+C at the REPL interrupts only the command running in the foreground. Background jobs and frozen jobs keep running.
When Nushell runs a script or a command given with nu -c, it stops any jobs that are still running, along with their child processes, before it exits. This also happens when the script was interrupted with Ctrl+C and the interruption was caught.
Calling exit inside a job's closure ends that job, not the shell.