Nushell
安装 Nu !
快速开始
  • Nushell 之书
  • 命令参考列表
  • 实战指南
  • 语言参考指南
  • 贡献指南
博客
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
  • 한국어
GitHub
安装 Nu !
快速开始
  • Nushell 之书
  • 命令参考列表
  • 实战指南
  • 语言参考指南
  • 贡献指南
博客
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
  • 한국어
GitHub
  • 简介
  • 安装
    • 默认 Shell
  • 快速入门
    • 快速入门
    • 在系统中四处移动
    • 用 Nu 的方式思考
    • Nushell 速查表
  • Nu 基础篇
    • 数据类型
    • 加载数据
    • 管道
    • 处理字符串
    • 处理列表
    • 处理记录
    • 处理表格
    • 导航和访问结构化数据
    • 特殊变量
  • Nushell 编程
    • 自定义命令
    • 别名
    • 运算符
    • 变量
    • 控制流
    • 脚本
    • 模块
      • 使用模块
      • 创建模块
    • 覆层
    • 排序
    • 测试你的 Nushell 代码
    • 脚本调试
    • 最佳实践
  • Nu 作为 Shell 使用
    • 配置
    • 环境
    • 标准输出、标准错误和退出码
    • 运行系统(外部)命令
    • 如何配置第三方提示
    • 目录栈
    • Reedline,Nu 的行编辑器
    • 自定义补全
    • 外部命令
    • Nu 的配色和主题
    • 钩子
    • 后台任务
  • 迁移到 Nu
    • 从 Bash 到 Nu
    • 从 CMD.EXE 到 Nu
    • 从 PowerShell 到 Nu
    • 从其他 Shell 或 DSL 到 Nu
    • 从命令式语言到 Nu
    • 从函数式语言到 Nu
    • Nushell 运算符对照
  • 设计说明
    • Nushell代码执行原理
  • (不怎么)高级篇
    • 标准库 (预览版)
    • Dataframes
    • 元数据
    • 创建你自己的错误
    • 并行
    • 插件
    • explore
    • 使用 tui 构建终端用户界面
    • MCP 服务器

加载数据

之前我们使用了ls、ps、date和sys host等命令来加载关于文件、进程、日期时间和系统本身的信息。每条命令都会给我们提供一个信息表,以对其进行探索。我们也可以通过其他方式将数据载入表格以供使用。

打开文件

Nu 在处理数据方面最强大的能力之一是open命令。它是一个多功能命令,可以处理许多不同的数据格式。为了说明这一点让我们试着打开一个 JSON 文件:

open editors/vscode/package.json
# => ╭──────────────────┬────────────────────────────────────────────────────────────────╮
# => │ name             │ lark                                                           │
# => │ description      │ Lark support for VS Code                                       │
# => │ author           │ Lark developers                                                │
# => │ license          │ MIT                                                            │
# => │ version          │ 1.0.0                                                          │
# => │                  │ ╭──────┬─────────────────────────────────╮                     │
# => │ repository       │ │ type │ git                             │                     │
# => │                  │ │ url  │ https://github.com/example/lark │                     │
# => │                  │ ╰──────┴─────────────────────────────────╯                     │
# => │ publisher        │ vscode                                                         │
# => │ categories       │ [list 0 items]                                                 │
# => │                  │ ╭───┬──────╮                                                   │
# => │ keywords         │ │ 0 │ lark │                                                   │
# => │                  │ ╰───┴──────╯                                                   │
# => │                  │ ╭────────┬────────╮                                            │
# => │ engines          │ │ vscode │ ^1.0.0 │                                            │
# => │                  │ ╰────────┴────────╯                                            │
# => │                  │ ╭───┬─────────────────╮                                        │
# => │ activationEvents │ │ 0 │ onLanguage:lark │                                        │
# => │                  │ ╰───┴─────────────────╯                                        │
# => │ main             │ ./out/extension                                                │
# => │                  │ ╭───────────────┬───────────────────╮                          │
# => │ contributes      │ │ configuration │ {record 0 fields} │                          │
# => │                  │ │ grammars      │ [list 0 items]    │                          │
# => │                  │ │ languages     │ [list 0 items]    │                          │
# => │                  │ ╰───────────────┴───────────────────╯                          │
# => │                  │ ╭───────────────────┬────────────────────────────────────────╮ │
# => │ scripts          │ │ compile           │ tsc                                    │ │
# => │                  │ │ postinstall       │ node ./node_modules/vscode/bin/install │ │
# => │                  │ │ test              │ npm run compile                        │ │
# => │                  │ │ vscode:prepublish │ npm run compile                        │ │
# => │                  │ │ watch             │ tsc -w                                 │ │
# => │                  │ ╰───────────────────┴────────────────────────────────────────╯ │
# => │                  │ ╭───────────────────────┬─────────╮                            │
# => │ devDependencies  │ │ @types/mocha          │ ^2.2.42 │                            │
# => │                  │ │ @types/node           │ ^7.0.43 │                            │
# => │                  │ │ tslint                │ ^5.8.0  │                            │
# => │                  │ │ typescript            │ ^2.6.1  │                            │
# => │                  │ │ vscode                │ ^1.1.6  │                            │
# => │                  │ │ vscode-languageclient │ ^3.5.0  │                            │
# => │                  │ ╰───────────────────────┴─────────╯                            │
# => ╰──────────────────┴────────────────────────────────────────────────────────────────╯

与ls类似,打开一个 Nu 支持的文件类型,会返回一些不仅仅是文本(或一个字节流)的东西。这里我们打开了一个来自 JavaScript 项目的 "package.json" 文件。Nu 可以识别 JSON 文本并将其解析为一个数据表。

如果我们想查看当前项目的版本,我们可以使用get命令:

open editors/vscode/package.json | get version
# => 1.0.0

Nu 目前支持直接从以下格式加载表数据:

  • csv
  • eml
  • ics
  • ini
  • json
  • kdl
  • md (Markdown)
  • msgpack / msgpackz
  • nuon
  • ods
  • plist
  • SQLite 数据库
  • ssv
  • toml
  • tsv
  • url
  • vcf
  • xlsx
  • xml
  • yaml / yml

eml、ics、ini、plist 和 vcf 格式由 formats 核心插件提供。

你知道吗?

在底层,open 会在你的作用域中查找与文件扩展名匹配的 from ... 子命令。 因此,你可以通过创建自己的 from ... 子命令来简单地扩展 open 支持的文件类型集。 save 以相同的方式查找匹配的 to ... 子命令。

转换器必须是用 def 定义的命令。像 alias "from jsonc" = from json 这样的别名行不通,open 和 save 会报错并提示等价的 def:

def "from jsonc" [] { from json }
open deno.jsonc

但是,当你加载其他的文本文件时会发生什么呢?让我们试一试:

open notes.txt
# => Remember to water the plants.
# => Call Mom on Sunday.

我们会看到该文件的内容。

本质上,这些文本文件对 Nu 来说就是一个大字符串。接下来,我们将讨论如何处理这些字符串,以便从中获得我们需要的数据。

NUON

Nushell 对象表示法(Nushell Object Notation,NUON)旨在成为 Nushell 的 JavaScript 对象表示法(JavaScript Object Notation,JSON)。 也就是说,NUON 代码是描述某种数据结构的有效 Nushell 代码。 例如,这是一个有效的 NUON(示例改编自已文档化的配置文件,你也可以用 config nu --doc 查看):

{
  menus: [
    # 默认 nushell 菜单的配置
    # 注意缺少 source 参数
    {
      name: completion_menu
      input_mode: cursor_prefix
      marker: "| "
      type: {
          layout: columnar
          columns: 4
          col_width: 20   # 可选值。如果缺少,则使用所有屏幕宽度来计算列宽
          col_padding: 2
      }
      style: {
          text: green
          selected_text: green_reverse
          description_text: yellow
      }
    }
  ]
}

你可能会注意到它与 JSON 非常相似,你是对的。 NUON 是 JSON 的超集! 也就是说,任何 JSON 代码都是有效的 NUON 代码,因此也是有效的 Nushell 代码。 与 JSON 相比,NUON 更“人性化”。 例如,允许注释,并且不需要逗号。

目前 NUON 的一个限制是它不能表示所有的 Nushell 数据类型。 最值得注意的是,NUON 不允许序列化闭包(to nuon --serialize 会把它们写成字符串,读回时不会还原成闭包)。

Markdown、KDL 和 YAML

Markdown

Markdown 是 open 能识别的格式之一,所以打开一个 .md 文件得到的不是字符串。以下面这个 README.md 为例, 先用 open --raw 把它作为文本显示:

open --raw README.md
# => # My Project
# =>
# => A short description.
# =>
# => ## Install
# =>
# => - Download it
# => - Run it

不加 --raw 时,from md 会把它转成一张表格, 每个标题、段落、列表项等各占一行:

open README.md | select element content
# => ╭───┬─────────┬──────────────────────╮
# => │ # │ element │       content        │
# => ├───┼─────────┼──────────────────────┤
# => │ 0 │ text    │ My Project           │
# => │ 1 │ text    │ A short description. │
# => │ 2 │ text    │ Install              │
# => │ 3 │ text    │ Download it          │
# => │ 4 │ text    │ Run it               │
# => ╰───┴─────────┴──────────────────────╯

这张表格还有一个 content_span 列,记录每个元素在文件中的位置;对于有属性的元素 (例如标题的层级),还会有 attributes 列。使用 from md --verbose 可以获取完整的语法树。

KDL

KDL 文档会被读取为一张节点表格。每一行包含节点的 name、 位置参数 args、具名属性 props 以及它的 children:

'package name=nu version="0.116.0"' | from kdl | get 0.props
# => ╭─────────┬─────────╮
# => │ name    │ nu      │
# => │ version │ 0.116.0 │
# => ╰─────────┴─────────╯

from kdl 默认按 KDL 2 版读取。读取 KDL 1 文档请使用 --spec 1。

YAML

from yaml 默认遵循 YAML 1.2, 所以像 yes 这样的值会保持为字符串而不会变成布尔值。 要按旧的 YAML 1.1 规则读取文件,请使用 --spec 1.1:

'enabled: yes' | from yaml
# => ╭─────────┬─────╮
# => │ enabled │ yes │
# => ╰─────────┴─────╯
'enabled: yes' | from yaml --spec 1.1
# => ╭─────────┬──────╮
# => │ enabled │ true │
# => ╰─────────┴──────╯

处理字符串

处理来自 Nu 外部数据时一个普遍情况是,它并不总是以 Nu 理解的格式出现。通常这些数据是以字符串的形式提供给我们的。

想象一下,我们得到了这个数据文件:

open people.txt
# => Octavia | Butler | Writer
# => Bob | Ross | Painter
# => Antonio | Vivaldi | Composer

我们想要的数据都由管道(|)符号隔开,每人单独一行。由于 Nu 没有默认的以管道分隔的文件格式,所以我们必须自己来解析。

当我们引入这个文件时,我们需要做的第一件事是确保后续每次只处理一行:

open people.txt | lines
# => ╭───┬──────────────────────────────╮
# => │ 0 │ Octavia | Butler | Writer    │
# => │ 1 │ Bob | Ross | Painter         │
# => │ 2 │ Antonio | Vivaldi | Composer │
# => ╰───┴──────────────────────────────╯

可以看到,我们正在处理这些行,因为我们又回到了一个列表中。下一步是看看是否可以把行分割成更有用的东西。为此,我们将使用split命令。split,顾名思义,为我们提供了一种分割字符串的方法。我们将使用split的column子命令,将内容分成多列。我们会告诉它分隔符是什么,剩下的就由它来完成:

open people.txt | lines | split column "|"
# => ╭───┬──────────┬───────────┬───────────╮
# => │ # │ column0  │  column1  │  column2  │
# => ├───┼──────────┼───────────┼───────────┤
# => │ 0 │ Octavia  │  Butler   │  Writer   │
# => │ 1 │ Bob      │  Ross     │  Painter  │
# => │ 2 │ Antonio  │  Vivaldi  │  Composer │
# => ╰───┴──────────┴───────────┴───────────╯

这看起来差不多了,只是还有一些额外的空白字符,让我们 trim 掉这些空格:

open people.txt | lines | split column "|" | str trim
# => ╭───┬─────────┬─────────┬──────────╮
# => │ # │ column0 │ column1 │ column2  │
# => ├───┼─────────┼─────────┼──────────┤
# => │ 0 │ Octavia │ Butler  │ Writer   │
# => │ 1 │ Bob     │ Ross    │ Painter  │
# => │ 2 │ Antonio │ Vivaldi │ Composer │
# => ╰───┴─────────┴─────────┴──────────╯

还不错,split命令返回给我们可以使用的数据,还预设了默认的列名:

open people.txt | lines | split column "|" | str trim | get column0
# => ╭───┬─────────╮
# => │ 0 │ Octavia │
# => │ 1 │ Bob     │
# => │ 2 │ Antonio │
# => ╰───┴─────────╯

我们也可以用自定义的列名代替默认的:

open people.txt | lines | split column "|" first_name last_name job | str trim
# => ╭───┬────────────┬───────────┬──────────╮
# => │ # │ first_name │ last_name │   job    │
# => ├───┼────────────┼───────────┼──────────┤
# => │ 0 │ Octavia    │ Butler    │ Writer   │
# => │ 1 │ Bob        │ Ross      │ Painter  │
# => │ 2 │ Antonio    │ Vivaldi   │ Composer │
# => ╰───┴────────────┴───────────┴──────────╯

现在,我们的数据加载到一个表中了,我们可以使用之前对表所用的各种命令来处理它:

open people.txt | lines | split column "|" first_name last_name job | str trim | sort-by first_name
# => ╭───┬────────────┬───────────┬──────────╮
# => │ # │ first_name │ last_name │   job    │
# => ├───┼────────────┼───────────┼──────────┤
# => │ 0 │ Antonio    │ Vivaldi   │ Composer │
# => │ 1 │ Bob        │ Ross      │ Painter  │
# => │ 2 │ Octavia    │ Butler    │ Writer   │
# => ╰───┴────────────┴───────────┴──────────╯

其他可用于字符串的命令有:

  • str
  • lines

如果我们已经知道待处理的数据具有 Nu 能够理解的格式,则可以使用一些辅助命令,例如,我们打开一个 Rust 的 Cargo.lock 文件:

open Cargo.lock | lines | first 6
# => ╭───┬───────────────────────────────────────────────────╮
# => │ 0 │ # This file is automatically @generated by Cargo. │
# => │ 1 │ # It is not intended for manual editing.          │
# => │ 2 │ version = 4                                       │
# => │ 3 │                                                   │
# => │ 4 │ [[package]]                                       │
# => │ 5 │ name = "adhoc_derive"                             │
# => ╰───┴───────────────────────────────────────────────────╯

"Cargo.lock" 实际上是一个 .toml 文件,但是文件扩展名不是 .toml。没关系,我们可以使用 from 命令和 toml 子命令:

open Cargo.lock | from toml | get package | select name version | first 3
# => ╭───┬──────────────┬─────────╮
# => │ # │     name     │ version │
# => ├───┼──────────────┼─────────┤
# => │ 0 │ adhoc_derive │ 0.1.2   │
# => │ 1 │ aho-corasick │ 1.1.5   │
# => │ 2 │ demo         │ 0.1.0   │
# => ╰───┴──────────────┴─────────╯

每种 Nu 能打开并理解的结构化数据文本格式都有对应的 from 命令可以使用,只需要把支持的格式作为子命令传给 from 就可以了。

以原始模式打开

虽然能够打开一个文件并立即使用其数据表很有帮助,但这并不总是我们想要的。为了获得原始文本,open命令可以接受一个可选的--raw标志:

open Cargo.toml --raw
# => [package]
# => name = "demo"
# => version = "0.1.0"
# => edition = "2024"
# =>
# => [dependencies]
# => adhoc_derive = "0.1.2"

SQLite

SQLite 数据库会被 open 自动检测,无论其文件扩展名是什么。要试一试,先用 into sqlite 创建一个小数据库:

[[name age]; [Alice 30] [Bob 25]] | into sqlite foo.db --table-name some_table

你可以打开整个数据库:

open foo.db
# => ╭────────────┬─────────────────────╮
# => │            │ ╭───┬───────┬─────╮ │
# => │ some_table │ │ # │ name  │ age │ │
# => │            │ ├───┼───────┼─────┤ │
# => │            │ │ 0 │ Alice │  30 │ │
# => │            │ │ 1 │ Bob   │  25 │ │
# => │            │ ╰───┴───────┴─────╯ │
# => ╰────────────┴─────────────────────╯

或者 get 一个特定的表:

open foo.db | get some_table
# => ╭───┬───────┬─────╮
# => │ # │ name  │ age │
# => ├───┼───────┼─────┤
# => │ 0 │ Alice │  30 │
# => │ 1 │ Bob   │  25 │
# => ╰───┴───────┴─────╯

或者运行任何你喜欢的 SQL 查询:

open foo.db | query db "select * from some_table where age > 26"
# => ╭───┬───────┬─────╮
# => │ # │ name  │ age │
# => ├───┼───────┼─────┤
# => │ 0 │ Alice │  30 │
# => ╰───┴───────┴─────╯

获取 URLs

除了从文件系统中加载文件,你还可以通过使用http get命令来加载 URLs。这将从互联网上获取 URL 的内容并返回:

http get https://blog.rust-lang.org/feed.xml
# => ╭────────────┬──────────────────╮
# => │ tag        │ feed             │
# => │ attributes │ {record 1 field} │
# => │ content    │ [table 18 rows]  │
# => ╰────────────┴──────────────────╯
在GitHub上编辑此页面
Contributors: Ibraheem Ahmed, Justin Ma, Filip Andersson, Hofer-Julian, amtoine, sophiajt, Jan Klass, 0x4D5352, voyage200🍬, qodelicious, Jianjun Wang, passionworkeer
Prev
数据类型
Next
管道