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 服务器

运算符

Nushell 支持以下运算符,用于常见的数学、逻辑和字符串操作:

运算符说明
+加
-减
*乘
/除
//向下取整除法
mod取模
**幂运算
==等于
!=不等于
<小于
<=小于等于
>大于
>=大于等于
=~ 或 like正则匹配 / 字符串包含另一个
!~ 或 not-like反向正则匹配 / 字符串不包含另一个
in值在列表中、字符串的子串、或记录中的键
not-in值不在列表中、不是子串、或不是记录中的键
has列表含有该值、字符串包含另一个、或记录含有该键
not-has列表不含该值、字符串不包含另一个、或记录缺少该键
not逻辑非
and两个布尔表达式的与(短路求值)
or两个布尔表达式的或(短路求值)
xor两个布尔表达式的异或
bit-or按位或
bit-xor按位异或
bit-and按位与
bit-shl按位左移
bit-shr按位右移
starts-with字符串以某内容开始
not-starts-with字符串不以某内容开始
ends-with字符串以某内容结尾
not-ends-with字符串不以某内容结尾
++连接两个列表、两个字符串或两个二进制值

括号可用于分组,以指定求值顺序,也可用于调用命令并在表达式中使用其结果。

运算顺序

要了解运算的优先级,可以运行命令:help operators | sort-by precedence -r。

按优先级从高到低排列,各运算如下:

  • 括号(())
  • 幂运算(**)
  • 乘(*)、除(/)、整数/向下取整除法(//)和取模(mod)
  • 加(+)和减(-)
  • 位移(bit-shl、bit-shr)
  • 比较运算(==、!=、<、>、<=、>=)、成员判断(in、not-in、has、not-has、starts-with、not-starts-with、ends-with、not-ends-with)、正则匹配(=~、!~、like、not-like)和连接(++)
  • 按位与(bit-and)
  • 按位异或(bit-xor)
  • 按位或(bit-or)
  • 逻辑非(not)
  • 逻辑与(and)
  • 逻辑异或(xor)
  • 逻辑或(or)
  • 赋值运算
3 * (1 + 2)
# => 9

类型

并非所有运算都适用于所有数据类型。 如果你尝试对不兼容的数据类型执行运算,会看到一条错误信息,它会解释哪里出了问题:

"spam" - 1
# => Error: nu::parser::operator_unsupported_type
# =>
# =>   × The '-' operator does not work on values of type 'string'.
# =>    ╭─[repl_entry #1:1:1]
# =>  1 │ "spam" - 1
# =>    · ───┬── ┬
# =>    ·    │   ╰── does not support 'string'
# =>    ·    ╰── string
# =>    ╰────

这些规则有时可能显得有点严格,但另一方面,意外副作用也会更少。

例如,++ 只能连接两个同类的值:两个列表、两个字符串或两个二进制值。要向列表中添加单个元素,请把该元素包成列表,或使用 append:

[1 2] ++ 3
# => Error: nu::parser::operator_unsupported_type
# =>
# =>   × The '++' operator does not work on values of type 'int'.
# =>    ╭─[repl_entry #2:1:7]
# =>  1 │ [1 2] ++ 3
# =>    ·       ─┬ ┬
# =>    ·        │ ╰── int
# =>    ·        ╰── does not support 'int'
# =>    ╰────
# =>   help: if you meant to append a value to a list or a record to a table, use the `append` command or wrap the value in a list. For example: `$list ++ $value` should be `$list ++ [$value]` or `$list
# =>         | append $value`.

[1 2] ++ [3]
# => ╭───┬───╮
# => │ 0 │ 1 │
# => │ 1 │ 2 │
# => │ 2 │ 3 │
# => ╰───┴───╯

正则表达式 / 字符串包含运算符

=~ 和 !~ 运算符提供了一种便捷的方式来计算正则表达式。你并不需要懂正则表达式才能使用它们——它们也是检查一个字符串是否包含另一个字符串的简便方法。

  • string =~ pattern:如果 string 中包含匹配 pattern 的内容则返回 true,否则返回 false。
  • string !~ pattern:如果 string 中包含匹配 pattern 的内容则返回 false,否则返回 true。

例如:

"foobarbaz" =~ "bar" # returns true
"foobarbaz" !~ "bar" # returns false
ls | where name =~ ^nu # returns all files whose names start with "nu"

这两个运算符都使用 Rust regex crate 的 is_match() 函数。

大小写敏感性

运算符作用于字符串时通常是区分大小写的。有几种方法可以进行不区分大小写的操作:

  1. 在正则表达式运算符中,指定 (?i) 不区分大小写模式修饰符:
"FOO" =~ "foo" # returns false
"FOO" =~ "(?i)foo" # returns true
  1. 使用 str contains 命令的 --ignore-case 标志:
"FOO" | str contains --ignore-case "foo"
  1. 比较前先用 str lowercase 把字符串转换成小写:
("FOO" | str lowercase) == ("Foo" | str lowercase)

展开运算符

Nushell 有一个用于展开列表和记录的展开运算符(...)。 如果你用过 JavaScript,可能对它并不陌生。有些语言用 * 作为它们的展开运算符。 它可以在需要多个值或多个键值对的地方展开列表或记录。

有三个地方可以使用展开运算符:

  • 在列表字面量中
  • 在记录字面量中
  • 在命令调用中

在列表字面量中

假设你有多个列表想要拼接在一起,但你同时 还想在中间插入一些单独的值。这可以用 append 和 prepend 完成,但展开 运算符能让你更轻松地做到。

let dogs = [Spot, Teddy, Tommy]
let cats = ["Mr. Humphrey Montgomery", Kitten]
[
  ...$dogs
  Polly
  ...($cats | each { |elt| $"($elt) \(cat\)" })
  ...[Porky Bessie]
  ...Nemo
]
# => ╭───┬───────────────────────────────╮
# => │ 0 │ Spot                          │
# => │ 1 │ Teddy                         │
# => │ 2 │ Tommy                         │
# => │ 3 │ Polly                         │
# => │ 4 │ Mr. Humphrey Montgomery (cat) │
# => │ 5 │ Kitten (cat)                  │
# => │ 6 │ Porky                         │
# => │ 7 │ Bessie                        │
# => │ 8 │ ...Nemo                       │
# => ╰───┴───────────────────────────────╯

下面是用 append 写的等价版本:

$dogs |
  append Polly |
  append ($cats | each { |elt| $"($elt) \(cat\)" }) |
  append [Porky Bessie] |
  append ...Nemo

请注意,每次调用 append 都会创建一个新列表,也就是说在第二个例子里 会多创建 3 个不必要的中间列表。使用展开运算符则不会如此, 所以如果你要反复拼接大量大型列表,使用 ... 可能会有 (非常轻微的)性能优势。

你可能已经注意到,上面结果列表的最后一项是 "...Nemo"。这是因为在列表字面量内部, 它只能用于展开列表,而不能用于展开字符串。因此,在列表字面量内部, 它只能用在变量(...$foo)、子表达式(...(foo))和列表字面量(...[foo])之前。

如果 ... 与后面的表达式之间有空白,它也不会被 识别为展开运算符:

[ ... [] ]
# => ╭───┬────────────────╮
# => │ 0 │ ...            │
# => │ 1 │ [list 0 items] │
# => ╰───┴────────────────╯

这主要是为了让 ... 在 mv ... $dir 这样的命令中不会被误认为是展开运算符。

在记录字面量中

假设你有一个包含若干配置信息的记录,你 想往这个记录里添加更多字段:

let settings = { path: /tmp, limit: 5 }

你可以用展开运算符创建一个新记录,它包含 $settings 的所有字段再加上一些新内容。 你可以在单个记录字面量中展开多个记录。

{
  ...$settings,
  users: [alice bob],
  ...{ url: example.com },
  ...(sys mem)
}
# => ╭────────────┬───────────────╮
# => │ path       │ /tmp          │
# => │ limit      │ 5             │
# => │            │ ╭───┬───────╮ │
# => │ users      │ │ 0 │ alice │ │
# => │            │ │ 1 │ bob   │ │
# => │            │ ╰───┴───────╯ │
# => │ url        │ example.com   │
# => │ total      │ 8.3 GB        │
# => │ free       │ 2.6 GB        │
# => │ used       │ 5.7 GB        │
# => │ available  │ 2.6 GB        │
# => │ swap total │ 2.1 GB        │
# => │ swap free  │ 18.0 MB       │
# => │ swap used  │ 2.1 GB        │
# => ╰────────────┴───────────────╯

与列表类似,在记录字面量内部,展开运算符也只能用在变量(...$foo)、 子表达式(...(foo))和记录字面量(...{foo:bar})之前。同样,... 与后面的表达式之间不能有空白,否则它不会被识别为展开运算符。

在命令调用中

你也可以把参数展开传给命令。列表可以展开传给具有剩余位置参数的命令 或外部命令,而记录可以展开传给 命名标志。

下面是一个具有剩余位置参数的自定义命令示例:

def foo [ --flag req opt? ...args ] {
  { flag: $flag, req: $req, opt: $opt, args: $args } | to nuon
}

它有一个标志(--flag)、一个必需的位置参数(req)、一个可选的位置参数 (opt?)和剩余位置参数(args)。

如果你有一个参数列表要传给 args,可以像 在列表字面量中展开列表那样展开它。同样的规则适用:展开运算符只能 用在变量、子表达式和列表字面量之前,且中间不能有空白。

foo "bar" "baz" ...[1 2 3] # With ..., the numbers are treated as separate arguments
# => {flag: false, req: bar, opt: baz, args: [1, 2, 3]}
foo "bar" "baz" [1 2 3] # Without ..., [1 2 3] is treated as a single argument
# => {flag: false, req: bar, opt: baz, args: [[1, 2, 3]]}

一个更有用的用法是:另一个命令也有剩余位置参数, 你想让它把参数转发给 foo:

def bar [ ...args ] { foo --flag "bar" "baz" ...$args }
bar 1 2 3
# => {flag: true, req: bar, opt: baz, args: [1, 2, 3]}

你可以在单次调用中展开多个列表,也可以在中间插入单独的参数:

foo "bar" "baz" 1 ...[2 3] 4 5 ...(6..9 | take 2) last
# => {flag: false, req: bar, opt: baz, args: [1, 2, 3, 4, 5, 6, 7, last]}

标志/命名参数可以放在展开的参数之后,就像它们可以放在常规剩余参数之后一样:

foo "bar" "baz" 1 ...[2 3] --flag 4
# => {flag: true, req: bar, opt: baz, args: [1, 2, 3, 4]}

如果展开的参数出现在可选位置参数之前,那么该可选参数 被视为省略:

foo "bar" ...[1 2] "not opt" # The null means no argument was given for opt
# => {flag: false, req: bar, opt: null, args: [1, 2, "not opt"]}

将记录展开为标志

可以把一个记录展开到命令调用中,用来传递命名标志。每个字段名就是一个标志名(不带前导的 --), 它的值就是该标志的值。对于 --flag 这样的开关,传 true 会启用它,而 false 或 null 则不启用。 这对内置命令和自定义命令都适用:

foo ...{ flag: true } "bar"
# => {flag: true, req: bar, opt: null, args: []}

let sort_options = { reverse: true }
[3 1 2] | sort ...$sort_options
# => ╭───┬───╮
# => │ 0 │ 3 │
# => │ 1 │ 2 │
# => │ 2 │ 1 │
# => ╰───┴───╯

字段的值会按标志的类型进行校验,如果某个字段匹配不上命令的任何标志,就会报错。 更多示例(包括需要取值的标志如何处理 null)参见 自定义命令。

在GitHub上编辑此页面
Contributors: Justin Ma, Hofer-Julian, Wenbo, 0x4D5352, Jan Klass, Solomon, voyage200🍬, Jianjun Wang, passionworkeer
Prev
别名
Next
变量