Job Control in Nushell

Effective Shell 书中的 Job Control 章节,介绍了如何在 Bash 中进行任务控制。感觉是比较有用的。本文将介绍其在 Nushell 中的用法。

Job Control

什么是Job Control,可以参考 Effective Shell/Job-Control#What-is-job-control

概括来讲,就是允许用户在前台和后台之间切换任务的能力

解决的问题

  1. 释放终端:将耗时任务转入后台运行,避免命令行被卡住,实现单窗口下的多任务并行。
  2. 挂起恢复:暂停当前程序(e.g. Vim)去处理突发事务,然后能无缝回到之前的工作状态。
    P.S: 如果使用Tmux/Zellij,也可以尝试使用floating pane来处理突发事务,参考我的这篇文章
  3. 任务管理:列出所有任务清单,清楚掌握谁在运行,并能随时关闭指定任务。

Job Management Overview

for UNIX Shell Users

  • 在命令末尾添加 & 来在后台运行命令
  • 使用 jobs 列出后台运行的命令
  • Ctrl-Z 将命令暂停并转为后台
  • 使用 fg 将后台运行的命令转入前台

Nushell built-in的job命令,提供了类似UNIX Shell的功能。使用help job可以查看其用法。

可以说Nushell和Powershell的命令十分语义化了。而UNIX Shell,设计偏简洁,会大量使用符号和缩写,依赖记忆,初学者难以理解其含义

$ help jobVarious commands for working with background jobs.You must use one of the following subcommands. Using this command as-is will only produce this help message.Usage:  > jobSubcommands:  job flush - Clear this job's mailbox.  job id - Get id of current job.  job kill - Kill a background job.  job list - List background jobs.  job recv - Read a message from the mailbox.  job send - Send a message to the mailbox of a job.  job spawn - Spawn a background job and retrieve its ID.  job tag - Add a description tag to a background job.  job unfreeze - Unfreeze a frozen process job in foreground.Flags:  -h, --help: Display the help message for this commandInput/output types:  ╭───┬─────────┬────────╮   #   input   output   ├───┼─────────┼────────┤   0  nothing  string   ╰───┴─────────┴────────╯

本文结束, 下面简单挑几个我感兴趣的子命令来介绍。

Spawn Background Jobs🫃🏻

Spawn ,意为孵化,在 Nushell 中表示启动一个后台任务

  • P.S. 第一次接触这个单词,是给Cyberpunk打Mod,生成NPC用的就是Spawn这个单词 (😡你这NPC衣服怎么没加载啊)

使用方法无需过多赘述,直接看例子,hexo clean; hexo gen 命令执行需要~10s,期间会阻塞交互,将其放在后台执行会方便些

# 启动后台任务$ job spawn { hexo clean; hexo gen }# 确认它正在后台默默工作$ job list╭───┬────┬────────┬──────────────╮ #  id   type       pids     ├───┼────┼────────┼──────────────┤ 0  34  thread  ╭───┬──────╮                  0  5359                  ╰───┴──────╯ ╰───┴────┴────────┴──────────────╯

关心任务的输出?暂时没找到Nushell对应的API,一个workaround是把stdout/stderr重定向到文件中:
hexo generate o> hexo.log e> hexo.err

Process Bound

当运行 job spawn { ... } 时,Nushell 实际上是在当前的 Shell 进程内部启动了一个新的Rust Thread来运行这个Closure[1],也就是说:

  • 多个Nushell进程之间的jobs是相互独立的,无法跨进程管理
  • 当前当你Exit Nushell后,后台任务也会被清理:
$ exitThere are still background jobs running (1).Running `exit` a second time will kill all of them.
BUG? Orphan Process Warning

虽然 Nushell 会尝试清理任务,但发现像 job spawn {hexo server} 这种启动了外部子进程node)清理得并不彻底,node进程不会死,而是变成了孤儿进程(Orphan Process)。在Github上提了个Issue job spawn terminates direct child but leaves grandchild processes orphaned · Issue #17378 · nushell/nushell

假设:

  • Parent: Nushell进程的PID是53822,
  • Child: hexo server启动的bun进程PID是64759
  • Grandchild: bun启动的node进程PID是64762

分别在exit nushell前后运行ps,查看它们的状态; 可以看到,Nushell退出后,bun进程被杀死了,但node进程的PPID变成了1(init进程),说明它并没有被清理掉

╭───┬───────┬──────┬──────┬────────┬──────┬─────────┬──────────┬─────────┬────────────────┬─────────┬──────────┬─────────────────┬──────────╮ #   pid   ppid  name  status  cpu     mem    virtual   command    start_time    user_id  priority  process_threads    cwd    ├───┼───────┼──────┼──────┼────────┼──────┼─────────┼──────────┼─────────┼────────────────┼─────────┼──────────┼─────────────────┼──────────┤ 0  53822  5135  nu    Sleep   0.00  38.0 MB  445.7 GB  -nu      21 minutes ago      501        31                5  /Users/g                                                                                                                      jx/Proje                                                                                                                      cts/dotf                                                                                                                      iles     ╰───┴───────┴──────┴──────┴────────┴──────┴─────────┴──────────┴─────────┴────────────────┴─────────┴──────────┴─────────────────┴──────────╯╭───┬───────┬───────┬──────┬────────┬──────┬────────┬──────────┬──────────────────────────────────┬───────────────┬─────────┬─────────┬─────╮ #   pid   ppid   name  status  cpu    mem    virtual               command                start_time    user_id  priorit  ...                                                                                                                   y            ├───┼───────┼───────┼──────┼────────┼──────┼────────┼──────────┼──────────────────────────────────┼───────────────┼─────────┼─────────┼─────┤ 0  64759  53822  bun   Sleep   0.00  5.3 MB  446.8 GB  /opt/homebrew/bin/bun run hexo s  2 minutes ago      501       31  ... ╰───┴───────┴───────┴──────┴────────┴──────┴────────┴──────────┴──────────────────────────────────┴───────────────┴─────────┴─────────┴─────╯╭────┬────────┬────────┬───────┬────────┬──────┬──────────┬──────────┬─────────┬───────────────┬─────────┬──────────┬─────────────────┬─────╮  #   pid     ppid   name   status  cpu     mem     virtual   command   start_time    user_id  priority  process_threads  cwd ├────┼────────┼────────┼───────┼────────┼──────┼──────────┼──────────┼─────────┼───────────────┼─────────┼──────────┼─────────────────┼─────┤  0   64762   64759  node   Sleep   0.00  229.3 MB  455.6 GB  hexo     2 minutes ago      501        31               15      ╰────┴────────┴────────┴───────┴────────┴──────┴──────────┴──────────┴─────────┴───────────────┴─────────┴──────────┴─────────────────┴─────╯
╭────────────╮ empty list ╰────────────╯╭────────────╮ empty list ╰────────────╯╭───┬───────┬──────┬──────┬────────┬──────┬──────────┬──────────┬─────────┬───────────────┬─────────┬──────────┬─────────────────┬─────╮ #   pid   ppid  name  status  cpu     mem     virtual   command   start_time    user_id  priority  process_threads  cwd ├───┼───────┼──────┼──────┼────────┼──────┼──────────┼──────────┼─────────┼───────────────┼─────────┼──────────┼─────────────────┼─────┤ 0  64762     1  node  Sleep   0.00  229.6 MB  455.6 GB  hexo     2 minutes ago      501        31               15      ╰───┴───────┴──────┴──────┴────────┴──────┴──────────┴──────────┴─────────┴───────────────┴─────────┴──────────┴─────────────────┴─────╯

Usage Scenarios

  • Uploading files
    • 一个具体的例子,Atuin的Nushell的脚本中,就使用了 job spawn 来创建上传的异步任务 [2]
  • Downloading files
  • Compile Code etc.

Freeze 🥶

就像在 UNIX Shell 中一样,你可以Freeze正在运行的前台进程:

  1. 在前台运行 hx ./test.js
  2. Ctrl+Z 或给进程发送 SIGTSTP信号; Nushell 报告:Job 20 is frozen
  3. Do something else…
  4. 使用 job unfreeze 20 可以将其恢复到前台继续运行

被冻结的任务不再消耗 CPU 资源,但仍然占用内存,并且保持着打开的文件句柄,等待用户下一步指令

Bash / ZshNushell
恢复到前台fg %1job unfreeze 20
杀死任务kill %1job kill 20
解冻并转后台跑bg %1Issue #15196

  1. An anonymous function, often called a lambda function, which accepts parameters and closes over (i.e., uses) variables from outside its scope Closure | Nushell ↩︎

  2. Atuin 是一款流行的Shell工具,它将Shell History Command持久化到SQLite数据库中,并支持将其同步到服务器,实现跨Shell+跨设备的历史命令同步 ↩︎

Job Control in Nushell

https://vluv.space/job_control/

Author

GnixAij

Posted

2026-01-19

Updated

2026-01-19

License