From 10fbabe91af3ff1a17a5cf311a4b653497bda1a4 Mon Sep 17 00:00:00 2001 From: passionworkeer Date: Sat, 31 Oct 2026 11:16:44 +0800 Subject: [PATCH 1/4] docs(zh-CN): complete the unfinished translations These zh-CN pages were translated only part-way and stopped mid-document, so readers hit a truncated page that looked like a complete one. This finishes the missing sections. Affected pages and what was missing: - externs.md: the last three limitations were missing entirely - metadata.md: about three quarters of the page - creating_errors.md: about two thirds of the page - running_externals.md: about two thirds of the page - explore.md, scripts.md, custom_completions.md, working_with_tables.md, working_with_lists.md, working_with_records.md, aliases.md: the remaining sections The existing wording was kept as-is where it was already translated; only the missing parts were added, so the diff shows additions rather than a rewrite. --- zh-CN/book/aliases.md | 185 ++++++-- zh-CN/book/creating_errors.md | 109 ++++- zh-CN/book/custom_completions.md | 355 +++++++++++---- zh-CN/book/explore.md | 115 ++++- zh-CN/book/externs.md | 173 +++++++- zh-CN/book/metadata.md | 164 ++++++- zh-CN/book/running_externals.md | 59 ++- zh-CN/book/scripts.md | 241 ++++++++-- zh-CN/book/working_with_lists.md | 244 ++++++++--- zh-CN/book/working_with_records.md | 118 ++++- zh-CN/book/working_with_tables.md | 682 +++++++++++++++++++---------- 11 files changed, 1942 insertions(+), 503 deletions(-) diff --git a/zh-CN/book/aliases.md b/zh-CN/book/aliases.md index 5ce84334a8e..4b827b127ba 100644 --- a/zh-CN/book/aliases.md +++ b/zh-CN/book/aliases.md @@ -1,49 +1,134 @@ # 别名 -Nushell 中的别名提供了一种简单的命令调用替换方式(包括外部和内部命令)。这允许你为一个较长的命令(包括其默认参数)创建一个简写名称。 +Nushell 中的别名提供了一种简单的命令调用替换方式(包括外部命令和内部命令)。这让你可以为一个较长的命令(包括其默认参数)创建一个简写名称。 -例如,让我们创建一个名为 `ll` 的别名,它将展开为 `ls -l`。 +例如,我们来创建一个名为 `ll` 的别名,它会展开为 `ls -l`。 ```nu alias ll = ls -l ``` -我们可以通过别名来调用它: +现在我们可以调用这个别名: ```nu ll ``` -一旦我们这样做了,就如同我们输入了 `ls -l` 一样。这也允许我们传入标志或位置参数。例如,我们现在也可以这样写: +一旦我们这样做了,就如同我们输入了 `ls -l` 一样。这也允许我们传入标志或位置参数。例如,我们现在还可以这样写: ```nu ll -a ``` -可得到与输入了`ls -l -a`一样的结果。 +得到的就相当于输入了 `ls -l -a`。 + +## 为父命令设置别名 + +别名也可以指向一个带有子命令的命令,例如 `math` 或 `str`。这样这些子命令也可以通过该别名使用: + +```nu +alias m = math +[1 2 3 4] | m sum +# => 10 +``` + +这对拥有许多子命令的插件尤其方便。例如,在执行 `alias pl = polars` 之后,你就可以写 `pl into-df`、`pl select` 和 `pl collect`。 ## 列出所有已加载的别名 -你可以在 `scope aliases` 和 `help aliases` 中看到所有可用的别名。 +你可以在 `scope aliases` 和 `help aliases` 中看到可用的别名。 + +对某个别名运行 `help` 会显示它展开成什么,随后是被别名指向的那个命令的帮助。例如,为一个小的自定义命令设置别名: + +```nu +# Say hello to someone +def greet [name: string] { $"Hello, ($name)!" } +alias hi = greet +help hi +# => Alias for `greet` +# => +# => Alias: hi +# => +# => Expansion: +# => greet +# => +# => Say hello to someone +# => +# => Usage: +# => > greet +# => +# => Flags: +# => -h, --help: Display the help message for this command +# => +# => Command Type: +# => > custom +# => +# => Parameters: +# => name +# => +# => Input/output types: +# => ╭───┬───────┬────────╮ +# => │ # │ input │ output │ +# => ├───┼───────┼────────┤ +# => │ 0 │ any │ any │ +# => ╰───┴───────┴────────╯ +``` + +当别名指向一个子命令时,对父命令运行 `help` 会以别名自身的名称列出该别名,紧跟在它所运行的子命令之后: + +```nu +# Manage notes +def notes [] {} +# Add a note +def "notes add" [text: string] {} +# List notes +def "notes list" [] {} +alias nl = notes list +help notes +# => Manage notes +# => +# => Usage: +# => > notes +# => +# => Subcommands: +# => notes add (custom) - Add a note +# => notes list (custom) - List notes +# => nl (alias) - Alias for `notes list` +# => +# => Flags: +# => -h, --help: Display the help message for this command +# => +# => Command Type: +# => > custom +# => +# => Input/output types: +# => ╭───┬───────┬────────╮ +# => │ # │ input │ output │ +# => ├───┼───────┼────────┤ +# => │ 0 │ any │ any │ +# => ╰───┴───────┴────────╯ +``` + +内置命令也同样如此:在执行 `alias st = str trim` 之后,`help str` 会在 `str trim` 之后紧跟着列出 `st (alias)`。隐藏命令和别名不会被列出。 ## 持久化 -为了使你的别名持久化,它必须被添加到你的 _config.nu_ 文件中。通过运行 `config nu` 打开编辑器并插入它们,然后重新启动 nushell。 -例如,对于上面的 `ll` 别名,你可以在 _config.nu_ 的任何地方添加 `alias ll = ls -l`。 +要使别名持久生效,必须把它们添加到你的 _config.nu_ 文件中:运行 `config nu` 打开编辑器并插入它们,然后重启 nushell。 +例如,对于上面的 `ll` 别名,你可以在 _config.nu_ 的任意位置添加 `alias ll = ls -l`。 ```nu $env.config = { - # 主要配置 + # main configuration } alias ll = ls -l -# 其他一些配置和脚本加载 +# some other config and script loading ``` ## 在别名中使用管道 -请注意,`alias uuidgen = uuidgen | tr A-F a-f`(使 mac 上的 uuidgen 行为与 linux 一致)将无法工作。 +请注意,`alias uuidgen = uuidgen | tr A-F a-f`(让 mac 上的 uuidgen 表现得像 linux 上一样)是行不通的。 解决方案是定义一个不带参数的命令,通过 `^` 调用系统程序 `uuidgen`。 ```nu @@ -52,67 +137,67 @@ def uuidgen [] { ^uuidgen | tr A-F a-f } 更多信息请参阅本书的[自定义命令](custom_commands.md)部分。 -或者一个更符合 nushell 风格的内部命令示例: +或者一个更符合 Nushell 风格的内部命令示例 ```nu def lsg [] { ls | sort-by type name -i | grid -c | str trim } ``` -在网格中显示所有列出的文件和文件夹。 +以网格形式显示所有列出的文件和文件夹。 ## 使用别名替换现有命令 -::: warning 警告! -替换命令时,最好先“备份”命令,以避免递归错误。 +::: warning 谨慎! +替换命令时,最好先“备份”该命令,以避免递归错误。 +::: + +::: tip 注意 +诸如 `if`、`for` 或 `let` 这样的解析器关键字无法被替换。把其中一个用作别名(或自定义命令)的名称会导致 `nu::parser::name_is_keyword` 错误。 ::: 如何备份像 `ls` 这样的命令: ```nu -alias core-ls = ls # 这将为 ls 创建一个名为 core-ls 的新别名 +alias core-ls = ls # This will create a new alias core-ls for ls ``` -现在你可以在你的 nu 编程中使用 `core-ls` 作为 `ls`。你将在下面看到如何使用 `core-ls`。 +现在即使 `ls` 本身已经被替换,你也可以在 nu 编程中把 `core-ls` 当作 `ls` 来使用。 -你需要使用别名的原因是,与 `def` 不同,别名是位置相关的。因此,在重新定义旧命令之前,你需要先用别名“备份”它。 -如果你不备份命令,而是使用 `def` 替换命令,你将会得到一个递归错误。 +你需要使用别名的原因是:与 `def` 不同,别名是位置相关的。所以,在重新定义旧命令之前,你需要先用别名“备份”它。 +如果你不备份命令,而是用 `def` 替换命令,就会得到递归错误。 ```nu -def ls [] { ls }; ls # *不要*这样做!这会抛出递归错误 - -#输出: -#Error: nu::shell::recursion_limit_reached -# -# × Recursion limit (50) reached -# ╭─[C:\Users\zolodev\AppData\Roaming\nushell\config.nu:807:1] -# 807 │ -# 808 │ def ls [] { ls }; ls -# · ───┬── -# · ╰── This called itself too many times -# ╰──── +def ls [] { ls }; ls # Do *NOT* do this! This will throw a recursion error +# => Error: nu::shell::recursion_limit_reached +# => +# => × Recursion limit (50) reached +# => ╭─[repl_entry #1:1:11] +# => 1 │ def ls [] { ls }; ls # Do *NOT* do this! This will throw a recursion error +# => · ───┬── +# => · ╰── This called itself too many times +# => ╰──── ``` -推荐的替换现有命令的方法是遮蔽(shadow)该命令。 -这是一个遮蔽 `ls` 命令的例子。 +推荐的替换现有命令的方式是遮蔽该命令,并在新定义中用 +`%` 符号调用原始的内置命令。`%ls` 始终运行内置的 `ls`,即使它被 +自定义命令或别名遮蔽,也不会产生递归。 +下面是一个遮蔽 `ls` 命令的例子。 ```nu -# 将内置的 ls 命令别名为 ls-builtins -alias ls-builtin = ls - -# 列出目录中项目的的文件名、大小和修改时间。 +# List the filenames, sizes, and modification times of items in a directory. def ls [ - --all (-a), # 显示隐藏文件 - --long (-l), # 获取每个条目的所有可用列(较慢;列取决于平台) - --short-names (-s), # 只打印文件名,不打印路径 - --full-paths (-f), # 将路径显示为绝对路径 - --du (-d), # 显示目录的视在大小(“磁盘使用情况”)而不是目录元数据大小 - --directory (-D), # 列出指定的目录本身而不是其内容 - --mime-type (-m), # 在类型列中显示 mime-type 而不是 'file'(仅基于文件名;不检查文件内容) - --threads (-t), # 使用多个线程列出内容。输出将是不确定的。 - ...pattern: glob, # 要使用的 glob 模式。 + --all (-a), # Show hidden files + --long (-l), # Get all available columns for each entry (slower; columns are platform-dependent) + --short-names (-s), # Only print the file names, and not the path + --full-paths (-f), # display paths as absolute paths + --du (-d), # Display the apparent directory size ("disk usage") in place of the directory metadata size + --directory (-D), # List the specified directory itself instead of its contents + --mime-type (-m), # Show mime-type in type column instead of 'file' (based on filenames only; files' contents are not examined) + --threads (-t), # Use multiple threads to list contents. Output will be non-deterministic. + ...pattern: glob, # The glob pattern to use. ]: [ nothing -> table ] { let pattern = if ($pattern | is-empty) { [ '.' ] } else { $pattern } - (ls-builtin + (%ls --all=$all --long=$long --short-names=$short_names @@ -125,3 +210,9 @@ def ls [ ) | sort-by type name -i } ``` + +你也可以在提示符下输入 `%ls`,以便在它被遮蔽时运行内置的 `ls`。 + +在 `%` 符号出现之前,函数体改为调用一个备份别名,例如用 `alias ls-builtin = ls` 创建的 `ls-builtin`。这种做法现在仍然有效,但前提是该别名是在 `ls` 仍指向内置命令时创建的。 + +有关 `%` 符号的更多内容,请参阅[遮蔽内置命令](custom_commands.md#遮蔽内置命令)。 diff --git a/zh-CN/book/creating_errors.md b/zh-CN/book/creating_errors.md index 94475b027c7..06fd0128dfb 100644 --- a/zh-CN/book/creating_errors.md +++ b/zh-CN/book/creating_errors.md @@ -4,8 +4,9 @@ - 错误的标题 - 错误信息的标签,其中包括标签的文本和要标注下划线的范围 +- 可选的帮助信息、错误码、URL,以及导致该错误的“内部”错误 -你可以使用`error make`命令来创建你自己的错误信息。例如,假设你有自己的名为`my-command`的命令,你想给调用者一个错误信息,说明传入的一个参数有问题。 +你可以使用 [`error make`](/commands/docs/error_make.md) 命令来创建你自己的错误信息。例如,假设你有自己的名为 `my-command` 的命令,你想给调用者一个错误信息,说明传入的一个参数有问题。 首先,你可以从参数的来源中获取标注范围: @@ -13,7 +14,7 @@ let span = (metadata $x).span; ``` -接下来你可以通过 `error make` 命令来创建一个错误,该命令需要一个可以描述待创建错误的记录作为输入: +接下来你可以通过 [`error make`](/commands/docs/error_make.md) 命令创建一个错误,该命令需要一个可以描述待创建错误的记录作为输入: ```nu error make {msg: "this is fishy", label: {text: "fish right here", span: $span } } @@ -38,11 +39,111 @@ def my-command [x] { ```nu my-command 100 -# => Error: +# => Error: nu::shell::error +# => # => × this is fishy -# => ╭─[entry #5:1:1] +# => ╭─[repl_entry #2:1:12] # => 1 │ my-command 100 # => · ─┬─ # => · ╰── fish right here # => ╰──── ``` + +如果你只需要一条消息,可以传入一个字符串而不是记录: + +```nu +error make "something went wrong" +# => Error: nu::shell::error +# => +# => × something went wrong +# => ╭─[repl_entry #3:1:1] +# => 1 │ error make "something went wrong" +# => · ────────── +# => ╰──── +``` + +## 多个标签与帮助 + +要在多处画下划线,请使用 `labels` 并传入一个标签列表,而不是 `label`。每个标签都是一个记录,包含 `span`(一个 `{start, end}` 记录,例如 `metadata` 返回的那种)和可选的 `text`。`help` 消息告诉用户如何解决这个问题: + +```nu +def check-range [lo: int, hi: int] { + if $lo > $hi { + error make { + msg: "invalid range" + labels: [ + {text: "lower bound" span: (metadata $lo).span} + {text: "is greater than the upper bound" span: (metadata $hi).span} + ] + help: "swap the two arguments" + } + } + $lo..$hi +} +``` + +```nu +check-range 10 1 +# => Error: nu::shell::error +# => +# => × invalid range +# => ╭─[repl_entry #5:1:13] +# => 1 │ check-range 10 1 +# => · ─┬ ┬ +# => · │ ╰── is greater than the upper bound +# => · ╰── lower bound +# => ╰──── +# => help: swap the two arguments +``` + +运行 `help error make` 可以查看错误还能包含哪些其它字段,例如 `code`、`url`、`inner` 和 `src`(用于指向另一个文件中的标签)。 + +## 捕获错误 + +当错误被 [`try`](/commands/docs/try.md) 捕获时,`catch` 闭包会收到一个描述该错误的记录: + +```nu +try { check-range 10 1 } catch {|err| $err.msg } +# => invalid range +``` + +除了 `msg`,这个记录还有 `debug`、`raw` 和 `rendered` 字段,以及一个 `details` 字段,它以结构化数据的形式保存错误的各个部分: + +```nu +try { check-range 10 1 } catch {|err| $err.details | reject labels inner } +# => ╭──────┬────────────────────────╮ +# => │ msg │ invalid range │ +# => │ code │ │ +# => │ url │ │ +# => │ help │ swap the two arguments │ +# => ╰──────┴────────────────────────╯ +``` + +::: note +在 Nushell 0.113 及更早版本中,这些信息以 JSON 字符串的形式存在于 `$err.json` 中。请改用 `$err.details`。 +::: + +## 串联错误 + +如果你在 `catch` 块中调用 `error make`,被捕获的错误会成为新错误的内部错误,两者都会被报告出来: + +```nu +try { check-range 10 1 } catch { error make "could not build the range" } +# => Error: nu::shell::error +# => +# => × could not build the range +# => ╭─[repl_entry #8:1:34] +# => 1 │ try { check-range 10 1 } catch { error make "could not build the range" } +# => · ────────── +# => ╰──── +# => +# => Error: +# => × invalid range +# => ╭─[repl_entry #8:1:19] +# => 1 │ try { check-range 10 1 } catch { error make "could not build the range" } +# => · ─┬ ┬ +# => · │ ╰── is greater than the upper bound +# => · ╰── lower bound +# => ╰──── +# => help: swap the two arguments +``` diff --git a/zh-CN/book/custom_completions.md b/zh-CN/book/custom_completions.md index cdc48078616..4b74a6d3105 100644 --- a/zh-CN/book/custom_completions.md +++ b/zh-CN/book/custom_completions.md @@ -1,50 +1,59 @@ # 自定义补全 -自定义补全允许你混合使用 Nushell 的两个功能:自定义命令和补全。有了它们,你就能够创建支持对位置参数和标志(Flags)参数进行自动补全的命令。这些自定义补全既适用于[自定义命令](custom_commands.md),也适用于 [已知的外部或`extern`命令](externs.md)。 +自定义补全允许你混合使用 Nushell 的两个功能:自定义命令和补全。有了它们,你就可以创建处理位置参数和标志参数补全的命令。这些自定义补全既适用于[自定义命令](custom_commands.md),也适用于[已知的外部或 `extern` 命令](externs.md)。 -补全分两步定义: +补全的定义分两步: -- 定义一个返回建议值的补全命令(又称 completer) +- 定义一个补全命令(又称补全器),返回可供建议的可能值 - 使用 `@` 将补全器附加到另一个命令参数的类型注解(shape)上 下面是一个简单的例子: ```nu -# 补全命令 +# Completion command def animals [] { ["cat", "dog", "eel" ] } -# 待补全的命令 +# Command to be completed def my-command [animal: string@animals] { print $animal } -my-command -# => cat dog eel +# Show what pressing Tab after `my-command ` would offer +'my-command ' | commandline complete +# => ╭───┬─────╮ +# => │ 0 │ cat │ +# => │ 1 │ dog │ +# => │ 2 │ eel │ +# => ╰───┴─────╯ ``` -第一行定义了一个自定义命令,它返回一个包含三种不同动物的列表。这些是补全中要使用的可能值。 +第一行定义了一个自定义命令,它返回一个包含三种不同动物的列表。这些就是补全的可能值。 ::: tip -要抑制参数的补全(例如,一个可以接受任何整数的 `int`),可以定义一个返回空列表 (`[ ]`) 的补全器。 +要为某个参数禁用补全(例如一个可以接受任意整数的 `int`),请定义一个返回空列表(`[ ]`)的补全器。 ::: -在第二行,`string@animals` 告诉 Nushell 两件事——用于类型检查的参数的形状,以及如果用户想在该位置补全输入值,需要使用的补全器。 +在第二行,`string@animals` 告诉 Nushell 两件事——用于类型检查的参数形状,以及为该参数建议可能值的补全器。 -第三行是补全的演示。输入自定义命令的名称 `my-command`,然后是一个空格,再按 Tab 键。这将显示一个包含可能补全的菜单。自定义补全的工作方式与系统中的其他补全相同,允许你输入 `e` 然后按 Tab 键自动补全 "eel"。 +要交互式地试用这个补全,输入自定义命令的名称 `my-command`,后跟一个空格,然后按 Tab 键。这会显示一个包含可能补全的菜单。自定义补全的工作方式与系统中的其他补全相同,你可以输入 `e` 后按 Tab 键自动补全“eel”。示例的最后一行使用 [`commandline complete`](/commands/docs/commandline_complete.md) 打印同样的建议,无需按 Tab(参见[测试补全器](#测试补全器))。 ::: tip -当补全菜单显示时,提示符默认会包含 `|` 字符。要更改提示标记,请在 `$env.config.menus` 列表的 `completion_menu` 记录中修改 `marker` 的值。另请参阅[补全菜单配置](/zh-CN/book/line_editor.md#completion-menu)。 +当补全菜单显示时,提示符默认会包含 `|` 字符。要更改提示标记,请修改 `$env.config.menus` 列表中 `name` 键为 `completion_menu` 的那条记录的 `marker` 值。另见[补全菜单配置](line_editor.md#补全菜单)。 ::: ::: tip -要回退到 Nushell 内置的文件补全,请返回 `null` 而不是建议列表。 +要回退到 Nushell 内置的文件补全,请返回 `null` 而不是建议列表。`null` 表示“我这里没有答案”,于是由下一个补全来源来响应;而空列表表示“没有可补全的内容”。 ::: ## 自定义补全选项 -如果你想选择如何过滤和排序你的补全,你也可以返回一个记录而不是列表。补全建议列表应位于此记录的 `completions` 键下。可选地,它还可以在 `options` 键下包含一个记录,其中包含以下可选设置: +如果你想选择补全的过滤和排序方式,也可以返回一个记录而不是列表。补全建议列表应放在该记录的 `completions` 键下。此外,它也可以在 `options` 键下放一个记录,包含以下可选设置: -- `sort` - 将此设置为 `false` 以阻止 Nushell 对你的补全进行排序。默认情况下,此值为 `true`,并且补全根据 `$env.config.completions.sort` 进行排序。 -- `case_sensitive` - 设置为 `true` 以使自定义补全区分大小写匹配,否则为 `false`。用于覆盖 `$env.config.completions.case_sensitive`。 -- `completion_algorithm` - 将此设置为 `prefix`、`substring` 或 `fuzzy` 以选择你的补全如何与键入的文本匹配。用于覆盖 `$env.config.completions.algorithm`。 +- `filter` - 设为 `true` 让 Nushell 根据已输入的文本过滤你的补全,设为 `false` 则完全按返回的内容显示。附加到参数上的补全器默认会被过滤。[外部补全器](#外部补全)默认不被过滤,因为它通常会自己做过滤。 +- `sort` - 设为 `false` 可以阻止 Nushell 对你的补全排序。默认为 `true`,补全会按 `$env.config.completions.sort` 排序。只有在 Nushell 同时过滤补全时才会排序。 +- `case_sensitive` - 设为 `true` 让自定义补全区分大小写匹配,否则设为 `false`。用于覆盖 `$env.config.completions.case_sensitive`。 +- `completion_algorithm` - 设为 `prefix`、`substring` 或 `fuzzy`,用于选择补全与已输入文本的匹配方式。用于覆盖 `$env.config.completions.algorithm`。 +- `match_description` - 设为 `true` 可让已输入的文本同时匹配每条建议的描述(除其值之外)。插入的补全仍然是建议的值。默认为 `false`。 -这是一个演示如何设置这些选项的示例: +该记录还可以有一个 `fallback` 键,详见[添加到内置补全](#添加到内置补全)。 + +下面是一个演示如何设置这些选项的例子: ```nu def animals [] { @@ -60,20 +69,69 @@ def animals [] { def my-command [animal: string@animals] { print $animal } ``` -现在,如果你尝试补全 `A`,你会得到以下补全: +现在,如果你尝试补全 `A`,会得到以下补全: ```nu ->| my-command A -cat rat bat +'my-command A' | commandline complete +# => ╭───┬─────╮ +# => │ 0 │ cat │ +# => │ 1 │ rat │ +# => │ 2 │ bat │ +# => ╰───┴─────╯ ``` -因为我们使匹配不区分大小写,Nushell 将在所有补全建议中找到子字符串 "a"。此外,因为我们设置了 `sort: false`,补全将保持其原始顺序。如果你的补全已经按与文本无关的特定顺序排序(例如按日期),这将非常有用。 +由于我们把匹配设为不区分大小写,Nushell 会在所有补全建议中找到子串“a”。此外,由于我们设置了 `sort: false`,补全将保持其原始顺序。如果你的补全已按与其文本无关的特定顺序(例如按日期)排好序,这会很有用。 + +### 匹配描述 + +自定义补全器可以选择让已输入的文本同时匹配建议的描述(除值之外),方法是在返回的 `options` 记录中设置 `match_description: true`。插入的补全仍然是建议的值。当值是一个不透明的标识符、而描述才是用户可能会输入的内容时,这很有用,例如按人名补全电子邮件地址: + +```nu +def "nu-complete users" [] { + { + options: { + match_description: true, + completion_algorithm: "substring", + }, + completions: [ + { value: "lk446763@example.com", description: "Lennart Kiil" }, + { value: "ab123456@example.com", description: "Alice Bob" }, + ] + } +} +def send-to [user: string@"nu-complete users"] { } +'send-to Lennart' | commandline complete +# => ╭───┬──────────────────────╮ +# => │ 0 │ lk446763@example.com │ +# => ╰───┴──────────────────────╯ +``` + +输入 `Lennart` 并按下 Tab 键会匹配描述“Lennart Kiil”并插入其值 `lk446763@example.com`,即使所输入的文本并没有出现在该值本身中。 + +### 添加到内置补全 + +通常,返回建议的补全器会取代 Nushell 自身对该参数的补全。在返回的记录中设置 `fallback: true`,可以既保留你的建议,又让下一个补全来源(例如文件补全)添加它自己的建议: + +```nu +def "nu-complete preset" [] { + {completions: ["@default"], fallback: true} +} +def build [target: string@"nu-complete preset"] { } +# In a directory containing `docs/`, `src/` and `notes.txt` +'build ' | commandline complete +# => ╭───┬───────────╮ +# => │ 0 │ @default │ +# => │ 1 │ docs/ │ +# => │ 2 │ notes.txt │ +# => │ 3 │ src/ │ +# => ╰───┴───────────╯ +``` -## 模块和自定义补全 +## 模块与自定义补全 -由于补全命令不应直接调用,因此通常在模块中定义它们。 +由于补全命令并不打算被直接调用,通常把它们定义在模块里。 -用模块扩展上面的例子: +用一个模块扩展上面的例子: ```nu module commands { @@ -87,17 +145,23 @@ module commands { } ``` -在此模块中,只导出了自定义命令 `my-command`。`animals` 补全未导出。这使得此模块的用户可以调用该命令,甚至使用自定义补全逻辑,而无需访问补全命令本身。这会产生更清晰、更易于维护的 API。 +在这个模块中,只有自定义命令 `my-command` 被导出。`animals` 补全没有被导出。这让模块的使用者可以调用该命令,甚至使用自定义补全的逻辑,却无法访问补全命令本身。这带来了更清晰、更易于维护的接口。 ::: tip -补全器在解析时使用 `@` 附加到自定义命令。这意味着,为了使对补全命令的更改生效,公共自定义命令也必须重新解析。导入模块通过单个 `use` 语句同时满足这两个要求。 +补全器是在解析时通过 `@` 附加到自定义命令上的。这意味着,要让补全命令的改动生效,公开的自定义命令也必须被重新解析。导入模块可以用一条 `use` 语句同时满足这两个要求。 ::: ## 上下文感知的自定义补全 -可以将上下文传递给补全命令。这在需要知道先前的参数或标志以生成准确补全的情况下很有用。 +补全器可以向 Nushell 询问补全发生位置的信息。在需要知道之前的参数或标志才能生成准确补全的情况下,这很有用。 + +补全器通过声明具有以下一个或多个名称(顺序不限)的参数来获取这些信息: + +- `token` - 描述光标下文本的记录:它的 `text`、它的 `kind`(`head`、`flag`、`value` 或 `block`),以及它在行中的 `span`。 +- `place` - 描述正在补全内容的记录。`kind` 说明光标所处位置的类型(例如 `positional`、`flag-name`、`flag-value` 或 `external-arg`),并在适用时带有 `index` 或 `flag`。`target` 是建议所替换的范围,而 `command` 是正在补全的命令(以单词列表表示),即使在管道之后、闭包内部或通过别名调用也一样。 +- `buffer` - 直到光标为止的整个命令行。 -将此概念应用于前面的示例: +把它应用到前面的例子: ```nu module commands { @@ -105,8 +169,8 @@ module commands { ["cat", "dog", "eel" ] } - def animal-names [context: string] { - match ($context | split words | last) { + def animal-names [place: record] { + match $place.command.1 { cat => ["Missy", "Phoebe"] dog => ["Lulu", "Enzo"] eel => ["Eww", "Slippy"] @@ -120,53 +184,160 @@ module commands { print $"The ($animal) is named ($name)." } } +use commands * ``` -在这里,命令 `animal-names` 返回适当的名称列表。`$context` 是一个字符串,其值是到目前为止已键入的命令行。 +这里,`animal-names` 命令返回相应的名字列表。补全 `my-command dog ` 时,`$place.command` 是 `[my-command, dog, ""]`,所以 `$place.command.1` 就是已经输入的动物。 ```nu ->| my-command -cat dog eel ->| my-command dog -Lulu Enzo ->my-command dog enzo -The dog is named Enzo +'my-command ' | commandline complete +# => ╭───┬─────╮ +# => │ 0 │ cat │ +# => │ 1 │ dog │ +# => │ 2 │ eel │ +# => ╰───┴─────╯ +'my-command dog ' | commandline complete +# => ╭───┬──────╮ +# => │ 0 │ Enzo │ +# => │ 1 │ Lulu │ +# => ╰───┴──────╯ +my-command dog Enzo +# => The dog is named Enzo. ``` -在第二行,按 tab 键后,参数 `"my-command dog"` 作为上下文传递给 `animal-names` 补全器。 - -::: tip -补全器还可以使用以下方式获取命令行上的当前光标位置: +要查看补全器在某个位置究竟会收到什么,请使用 `commandline complete --input`: ```nu -def completer [context:string, position:int] {} +def my-command [animal: string, name: string] {} +'ls | my-command dog L' | commandline complete --input +# => ╭────────┬──────────────────────────────────╮ +# => │ │ ╭──────┬────────────────╮ │ +# => │ token │ │ text │ L │ │ +# => │ │ │ kind │ value │ │ +# => │ │ │ │ ╭───────┬────╮ │ │ +# => │ │ │ span │ │ start │ 20 │ │ │ +# => │ │ │ │ │ end │ 21 │ │ │ +# => │ │ │ │ ╰───────┴────╯ │ │ +# => │ │ ╰──────┴────────────────╯ │ +# => │ │ ╭─────────┬────────────────────╮ │ +# => │ place │ │ cursor │ 21 │ │ +# => │ │ │ │ ╭───────┬────╮ │ │ +# => │ │ │ target │ │ start │ 20 │ │ │ +# => │ │ │ │ │ end │ 21 │ │ │ +# => │ │ │ │ ╰───────┴────╯ │ │ +# => │ │ │ kind │ positional │ │ +# => │ │ │ index │ 1 │ │ +# => │ │ │ shape │ string │ │ +# => │ │ │ │ ╭───┬────────────╮ │ │ +# => │ │ │ command │ │ 0 │ my-command │ │ │ +# => │ │ │ │ │ 1 │ dog │ │ │ +# => │ │ │ │ │ 2 │ L │ │ │ +# => │ │ │ │ ╰───┴────────────╯ │ │ +# => │ │ ╰─────────┴────────────────────╯ │ +# => │ buffer │ ls | my-command dog L │ +# => ╰────────┴──────────────────────────────────╯ ``` +::: tip +在补全器内部请使用 `buffer`,而不是调用 `commandline`:`buffer` 始终是被补全的那一行。如果你需要把该行拆分成词法单元,请 `use std/util` 并调用 `util structure $buffer`,它会返回一个 `{text, kind, span}` 表格。 +::: + +::: warning +较旧的补全器声明为 `[context: string]`(可选地带有第二个 `position: int` 参数),或对外部和命令级补全器声明为 `[spans: list]`。它们仍然会收到旧的值,但 Nushell 会在首次使用时打印一条 `Positional completer input deprecated` 警告。请改用 `buffer`、`place` 或 `token`:`$buffer` 取代旧的 context 字符串,`$place.cursor` 取代位置,`$place.command` 取代 `spans`。 ::: -## 自定义补全和 [`extern`](/commands/docs/extern.md) +## 自定义补全与 [`extern`](/commands/docs/extern.md) -一个强大的组合是为 [已知的`extern`命令](externs.md) 添加自定义补全。这些工作方式与向自定义命令添加自定义补全的方式相同:通过创建自定义补全,然后用`@`附加到 `extern` 的一个位置参数或标志参数的类型中。 +一个强大的组合是为[已知的 `extern` 命令](externs.md)添加自定义补全。其工作方式与为自定义命令添加自定义补全相同:创建自定义补全,然后用 `@` 把它附加到 `extern` 的某个位置参数或标志参数的类型上。 -如果你仔细看一下默认配置中的例子,你会看到这个: +例如,以下是 [nu_scripts 仓库](https://github.com/nushell/nu_scripts/blob/main/custom-completions/git/git-completions.nu) 中 `git push` 补全的简化版本: ```nu +def "nu-complete git remotes" [] { + ^git remote | lines +} + +def "nu-complete git branches" [] { + ^git branch --format '%(refname:short)' | lines +} + export extern "git push" [ remote?: string@"nu-complete git remotes", # the name of the remote - refspec?: string@"nu-complete git branches" # the branch / refspec - ... + ...refs: string@"nu-complete git branches" # the branch / refspec + --all # push all refs + --force(-f) # force updates ] ``` -自定义补全在这个例子中的作用与前面的例子中的作用相同。上面的例子根据用户当前所处的位置,调用了两个不同的自定义补全。 +在 git 仓库中,`git push ` 现在会提供远程的名称,而 `git push origin ` 会提供本地分支。 -## 自定义描述和样式 +自定义补全在本例中的作用与前几个例子相同。上面的例子根据用户当前所处的位置调用两个不同的自定义补全。 -作为返回字符串列表的替代方法,补全函数还可以返回一个记录列表,其中包含一个 `value` 字段以及可选的 `description` 和 `style` 字段。样式可以是以下之一: +## 命令级补全器 -- 一个带有前景色的字符串,可以是十六进制代码或颜色名称,例如 `yellow`。有关有效颜色名称的列表,请参阅 `ansi --list`。 -- 一个包含 `fg`(前景色)、`bg`(背景色)和 `attr`(属性,如带下划线和粗体)字段的记录。此记录的格式与 `ansi --escape` 接受的格式相同。有关 `attr` 字段的可能值列表,请参阅 [`ansi`](/commands/docs/ansi) 命令参考。 -- 相同的记录,但转换为 JSON 字符串。 +除了把补全器附加到每个参数上,你还可以用 [`@complete`](/commands/docs/attr_complete.md) 属性把一个补全器附加到命令的所有参数上。这对接受自由形式参数列表的命令很方便。命令级补全器会为每个参数调用,且 Nushell 不会过滤它返回的内容,所以它通常自己按 `$token.text` 过滤: + +```nu +def "nu-complete deploy" [token: record, place: record] { + let candidates = if ($place.command | length) <= 2 { + [staging production] + } else { + [--dry-run --force] + } + $candidates | where $it starts-with $token.text +} + +@complete "nu-complete deploy" +def deploy [...args: string] { $args } + +'deploy p' | commandline complete +# => ╭───┬────────────╮ +# => │ 0 │ production │ +# => ╰───┴────────────╯ +'deploy staging --d' | commandline complete +# => ╭───┬───────────╮ +# => │ 0 │ --dry-run │ +# => ╰───┴───────────╯ +``` + +`@complete external` 则改为把命令的参数发送给[外部补全器](#外部补全)。把它用于与被包装的外部命令同名的包装器,这样外部补全器就知道它正在补全哪个命令: + +```nu +@complete external +def --wrapped jc [...args] { + ^jc ...$args | from json +} +``` + +`def --wrapped` 命令会把它未声明的标志传给它的剩余参数。因此,附加在该剩余参数上的补全器也会为以 `-` 开头的参数调用,其建议会与命令自身的标志一起列出: + +```nu +def "nu-complete what" [] { [--verbose --color=always plain] } +def --wrapped what [--local, ...args: string@"nu-complete what"] { $args } + +'what --' | commandline complete +# => ╭───┬────────────────╮ +# => │ 0 │ --local │ +# => │ 1 │ --color=always │ +# => │ 2 │ --verbose │ +# => ╰───┴────────────────╯ +``` + +## 自定义描述与样式 + +除了返回字符串列表,补全函数也可以返回一个记录列表,其中带有 `value` 字段以及下列可选字段: + +- `description` - 菜单中显示在值旁边的文本。 +- `style` - 菜单中值的着色方式(见下文)。 +- `display_override` - 菜单中显示(并与已输入文本匹配)的文本,用来代替 `value`。插入的文本仍然是 `value`。 +- `span` - 一个 `{start, end}` 记录,以字节偏移给出该值所替换的行的一部分。默认情况下,该值替换正在补全的词法单元。 +- `extra` - 与所选值一起显示的字符串列表。它只出现在 `description` 菜单中。 + +样式可以是以下之一: + +- 前景色字符串,可以是十六进制代码或颜色名,例如 `yellow`。有效颜色名的列表请见 `ansi --list`。 +- 带有 `fg`(前景色)、`bg`(背景色)和 `attr`(如下划线、粗体等属性)字段的记录。该记录与 `ansi --escape` 接受的格式相同。`attr` 字段的可能取值列表请参阅 [`ansi`](/commands/docs/ansi) 命令参考。 +- 同样的记录,但转换为 JSON 字符串。 ```nu def my_commits [] { @@ -179,7 +350,7 @@ def my_commits [] { ``` ::: tip 注意 -使用以下代码段: +使用下面的代码片段: ```nu def my-command [commit: string@my_commits] { @@ -187,45 +358,77 @@ def my-command [commit: string@my_commits] { } ``` -... 请注意,即使补全菜单会向你显示类似 +... 请注意,即使补全菜单会显示类似下面的内容 ```ansi ->_ my-command -5c2464 Add .gitignore -f3a377 Initial commit +>_ [36mmy-command[0m +[1;31m5c2464[0m [33mAdd .gitignore[0m +[1;4;48;2;102;7;140;32mf3a377 [0m[33mInitial commit[0m ``` -... 的内容,也只有值(即 "5c2464" 或 "f3a377")将用于命令参数! +... 只有值(即“5c2464”或“f3a377”)会被用在命令参数中! ::: -## 外部补全 +## 交互式补全器 -也可以集成外部补全器,而不是仅仅依赖于 Nushell 的补全器。 +补全器通常在后台运行,因此缓慢的补全器永远不会阻塞行编辑器。需要终端的补全器,例如启动 `fzf` 之类的模糊查找器或使用 [`input list`](/commands/docs/input_list.md) 的补全器,必须用 [`@interactive`](/commands/docs/attr_interactive.md) 属性标记。它随后在前台运行并独占终端,它返回的任何内容都会成为补全: -为此,请将 `config.nu` 中的 `external_completer` 字段设置为一个[闭包](types_of_data.md#closures),如果未找到 Nushell 补全,则将对其进行求值。 +```nu +@interactive +def pick-file [token: record] { + ls | get name | to text | ^fzf --query $token.text | lines +} + +def open-file [path: string@pick-file] { + open $path +} +``` + +输入 `open-file ` 并按下 Tab 会打开 `fzf`,你选择的文件会被插入到命令行中。如果你改为取消选择器(例如按 Esc),则不会插入任何内容,也不会有菜单保持打开;再次按 Tab 会重新打开选择器。 + +## 测试补全器 + +[`commandline complete`](/commands/docs/commandline_complete.md) 命令对一个字符串运行补全引擎,就像光标位于其末尾一样。这让你可以不按 Tab 就检查补全器: + +- `commandline complete` 返回建议的值。 +- `commandline complete --detailed` 以记录形式返回建议,格式与自定义补全器返回的相同。 +- `commandline complete --input` 返回补全器会收到的 `{token, place, buffer}` 记录,而不运行任何补全器。 +- `commandline complete --type ` 只运行 Nushell 的某一个内置补全来源(`directory`、`path`、`glob`、`command`、`variable` 或 `env-var`)。补全器可以用它把 Nushell 自身的建议与它自己的建议结合起来: ```nu -$env.config.completions.external = { - enable: true - max_results: 100 - completer: $completer +def "nu-complete dirs-or-default" [token: record] { + ['@default'] ++ ($token.text | commandline complete --type directory) } +def build [target: string@"nu-complete dirs-or-default"] { } +# In a directory containing `docs/`, `src/` and `notes.txt` +'build ' | commandline complete +# => ╭───┬──────────╮ +# => │ 0 │ @default │ +# => │ 1 │ docs/ │ +# => │ 2 │ src/ │ +# => ╰───┴──────────╯ ``` -你可以配置闭包以运行外部补全器,例如 [carapace](https://github.com/rsteube/carapace-bin)。 +## 外部补全 -外部补全器是一个函数,它接受当前命令作为字符串列表,并输出一个带有 `value` 和 `description` 键的记录列表,就像自定义补全函数一样。当闭包返回 `null` 时,它默认为文件补全。 +除了只依赖 Nushell 自带的补全器,外部补全器也可以被集成进来。 -::: tip 注意 -此闭包将接受当前命令作为列表。例如,键入 `my-command --arg1 ` 将接收 `[my-command --arg1 " "]`。 -::: +为此,请在 `config.nu` 中把 `$env.config.completions.external.completer` 设为一个[闭包](types_of_data.md#闭包)。Nushell 会调用它来补全外部命令的参数,即那些不是内置、自定义或 [`extern`](externs.md) 命令的命令。与其它补全器一样,该闭包通过命名其参数来请求 `token`、`place` 或 `buffer`,并且可以返回与自定义补全器相同的值。当闭包返回 `null` 时,Nushell 回退到文件补全。 + +大多数外部补全器只需要 `$place.command`,即正在补全的命令(以单词列表表示)。例如,输入 `git checkout ma` 并按下 Tab 会让闭包收到 `[git, checkout, ma]`,而输入 `my-command --arg1 ` 会收到 `[my-command, --arg1, ""]`,其中尚未输入的参数用空字符串表示。别名已经被展开:如果 `gco` 是 `git checkout` 的别名,输入 `gco ma` 同样会得到 `[git, checkout, ma]`。 -此示例将启用 carapace 外部补全: +你可以配置该闭包来运行一个外部补全器,例如 [carapace](https://github.com/carapace-sh/carapace-bin)。下面这个例子会启用 carapace 外部补全: ```nu -let carapace_completer = {|spans| - carapace $spans.0 nushell ...$spans | from json +$env.config.completions.external.completer = {|place| + carapace $place.command.0 nushell ...$place.command | from json } ``` -[更多外部补全器的示例可以在 实战指南 中找到](../cookbook/external_completers.md)。 +::: tip 注意 +`$env.config.completions.external` 中的 `enable` 和 `max_results` 设置控制补全命令名时是否(以及提供多少个)来自你 `PATH` 的外部命令名。它们不影响外部补全器。 +::: + +要对自定义命令也使用外部补全器,请用 [`@complete external`](#命令级补全器) 标记该命令。 + +[更多外部补全器的例子可以在 cookbook 中找到](../cookbook/external_completers.md)。 diff --git a/zh-CN/book/explore.md b/zh-CN/book/explore.md index 7d54f611415..1bc4595f94a 100644 --- a/zh-CN/book/explore.md +++ b/zh-CN/book/explore.md @@ -1,17 +1,17 @@ # `explore` -explore是一个表格分页器,类似于`less`,但用于表格结构化数据。 +[`explore`](/commands/docs/explore.md) 是一个表格分页器,类似于 `less`,但面向结构化数据。把任意值用管道传给它,就可以滚动浏览、深入查看嵌套的记录和表格、搜索,并对你正在查看的内容运行 Nushell 命令。 ## 签名 -`> explore --head --index --reverse --peek` +`> explore --head --index --tail --peek` ### 参数 -- `--head {bool}`: 显示或隐藏列标题(默认为true) -- `--index, -i`: 查看列表时显示行索引 -- `--tail, -t`: 从底部开始滚动视口 -- `--peek, -p`: 退出时输出光标所在单元格的值 +- `--head `:显示或隐藏列标题(默认 `true`) +- `--index, -i`:查看列表时显示行索引 +- `--tail, -t`:视口初始滚动到底部 +- `--peek, -p`:退出时输出光标所在单元格的值 ## 快速开始 @@ -21,26 +21,73 @@ ls | explore -i ![explore-ls-png](https://user-images.githubusercontent.com/20165848/207849604-421312e3-537f-4b2e-b83e-f1f83f2a79d5.png) -[`explore`](/commands/docs/explore.md)的主要功能是`:table`(你可以在上面的截图中看到)。 +还有几种启动方式: -你可以通过``、``、``、``方向键与之交互。它还支持Vim风格的``、``、``、``键绑定,``和``,以及Emacs风格的``、``、``和``键绑定。 +```nu +# Explore the system host information record +sys host | explore + +# Explore the output of ls without column names +ls | explore --head false + +# Start at the end of a long list +help commands | explore --tail + +# Explore a JSON file, then save the part you were looking at when you quit +open file.json | explore --peek | to json | save part.json +``` + +## 移动浏览 + +| 按键 | 动作 | +| -------------------------------------------------------------- | -------------------------------------------- | +| 方向键,或 `h` `j` `k` `l` | 移动光标 | +| `Ctrl+p` / `Ctrl+n` | 向上 / 向下移动(Emacs 风格) | +| `PageUp` / `PageDown`、`Ctrl+b` / `Ctrl+f`、`Alt+v` / `Ctrl+v` | 向上 / 向下翻页 | +| `Home` / `End`,或 `g` / `G` | 跳到第一行 / 最后一行 | +| `Enter` 或 `i` | 进入光标模式;在光标模式下深入查看所选单元格 | +| `Esc` 或 `q` | 退出光标模式;否则返回上一层,在顶层则退出 | +| `t` | 转置(行列互换),在视图模式下 | +| `e` | 展开(显示所有嵌套数据) | -你可以通过进入光标模式来检查底层值。按``或``进入该模式。 -然后使用方向键选择需要的单元格。 -你将能够看到它的底层结构。 +`explore` 以 _视图_ 模式启动(状态栏显示 `VIEW`),此时方向键滚动表格。按 `Enter`(或 `i`)切换到 _光标_ 模式(状态栏显示 `EDIT`),此时方向键让光标在单元格之间移动。在存放记录或列表的单元格上再按一次 `Enter`,会在新视图中打开它,这样你就能逐层深入嵌套数据。按 `Esc` 退出光标模式,再按一次则返回上一层。 -你可以通过`:help`获取更多相关信息。 +## 搜索 + +按 `/` 向前搜索,或按 `?` 向后搜索。结果会随着你的输入高亮显示。然后用 `n` 和 `N` 在匹配项之间移动。 ## 命令 -[`explore`](/commands/docs/explore.md)有一系列内置命令可供使用。通过按`<:>`然后输入命令名称来运行命令。 +[`explore`](/commands/docs/explore.md) 带有几个内置命令。按 `:` 然后输入命令名称: -要查看完整的命令列表,可以输入`:help`。 +| 命令 | 动作 | +| ----------- | ----------------------------- | +| `:help` | 显示帮助页面 | +| `:try` | 在当前数据上打开交互式 REPL | +| `:nu ` | 在当前数据上运行 Nushell 命令 | +| `:q` | 退出 `explore` | ## 配置 -你可以通过配置自定义许多选项(包括样式和颜色)。 -你可以在[`default-config.nu`](https://github.com/nushell/nushell/blob/main/crates/nu-utils/src/default_files/default_config.nu)中找到示例配置。 +`explore` 的颜色在 `$env.config.explore` 中配置。每个取值都与 [`color_config`](coloring_and_theming.md) 的形式相同:颜色名、`#RRGGBB` 十六进制代码,或 `{fg, bg, attr}` 记录。例如: + +```nu +$env.config.explore = { + selected_cell: { bg: light_blue } + highlight: { fg: black, bg: yellow } + title_bar_text: { fg: white } + title_bar_background: { bg: blue } + status: { + success: { fg: black, bg: green } + error: { fg: white, bg: red } + } + try: { reactive: false } +} +``` + +支持的键有 `selected_cell`、`highlight`、`status_bar_text`、`status_bar_background`、`command_bar_text`、`command_bar_background`、`title_bar_text`、`title_bar_background`、`status`(包含 `info`、`success`、`warn` 和 `error` 条目),以及 `try.reactive`。当 `try.reactive` 为 `true` 时,`:try` 会在你输入时重新运行命令,而不只是在你按 `Enter` 时才运行。 + +运行 `config nu --doc` 可以查看每个键的文档和默认值。 ## 示例 @@ -52,14 +99,42 @@ $nu | explore --peek ![explore-peek-gif](https://user-images.githubusercontent.com/20165848/207854897-35cb7b1d-7f7d-4ae2-9ec8-df19ac04ac99.gif) -### `:try`命令 +### `:try` 命令 -有一个交互式环境,你可以使用`nu`命令浏览数据。 +有一个交互式环境,你可以用 `nu` 在其中浏览数据。 ![explore-try-gif](https://user-images.githubusercontent.com/20165848/208159049-0954c327-9cdf-4cb3-a6e9-e3ba86fde55c.gif) -#### 通过`$nu`保留所选值 +#### 用 `$nu` 保留所选的值 -记住你可以结合`--peek`参数使用。 +记住你可以将它与 `--peek` 结合使用。 ![explore-try-nu-gif](https://user-images.githubusercontent.com/20165848/208161203-96b51209-726d-449a-959a-48b205c6f55a.gif) + +## 浏览你的配置 + +[`explore config`](/commands/docs/explore_config.md) 会把你当前的 `$env.config` 作为一棵树打开,并带有一个编辑窗格。用 `Tab` 在树和编辑器之间切换,用方向键移动以及展开或折叠节点,用 `Enter` 开始编辑某个值。按 `Ctrl+S` 应用编辑。用 `q` 退出时,你的改动会应用到当前会话;`Ctrl+C` 则不保存退出。 + +```nu +# Browse and edit the running configuration +explore config + +# Explore any JSON data as a tree +open --raw data.json | explore config + +# Print the tree without starting the TUI +open --raw data.json | explore config --tree +``` + +## 构建正则表达式 + +[`explore regex`](/commands/docs/explore_regex.md) 会打开一个交互式编辑器,用于在示例文本上构建和测试正则表达式。按 `Ctrl+Q` 退出,你所构建的表达式会被返回: + +```nu +let pattern = open notes.txt | explore regex +open notes.txt | lines | where $it =~ $pattern +``` + +## 构建你自己的界面 + +`explore` 是一个现成的查看器。要构建你自己的交互式界面,例如选择器、表单或仪表板,请参阅[用 `tui` 构建终端用户界面](tui.md)。 diff --git a/zh-CN/book/externs.md b/zh-CN/book/externs.md index aeee2141029..7c7f70a280d 100644 --- a/zh-CN/book/externs.md +++ b/zh-CN/book/externs.md @@ -38,13 +38,13 @@ use "ssh extern" ssh - 将提供 `-p` 和 `-i`(带描述)作为 `ssh -` 的可能补全。 - 将执行解析时类型检查。试图为端口号使用非 `int` 将导致错误(和错误条件的语法高亮)。 - 将根据参数的形状提供解析时语法高亮。 -- 将提供 `~/.ssh` 中的任何私钥文件作为 `-i`(身份)选项的补全值。 -- 将不为目标主机提供补全。如果没有返回空列表的补全器,Nushell 将尝试使用默认的“文件”补全器。 +- 将提供 `~/.ssh` 中的任何私钥文件作为 `-i`(身份)标志的补全值。 +- 将不为目标主机提供补全。如果没有返回空列表的补全器,Nushell 将尝试使用默认的“File”补全器。 有关从 SSH 配置文件中检索主机的实现,请参阅 [Nu_scripts 仓库](https://github.com/nushell/nu_scripts/blob/main/custom-completions/ssh/ssh-completions.nu)。 ::: tip 提示 -用于参数文档目的的 Nushell 注释,如果与参数在同一行,则需要在 `#` 井号之前加一个空格。 +用于参数文档目的的 Nushell 注释,如果与参数在同一行,则需要在 ` #` 井号之前加一个空格。 ::: ## 格式说明符 @@ -58,11 +58,174 @@ export extern "git add" [ ] ``` +## 结构化输出 + +许多外部命令在你传入某个标志时会输出机器可读的结果,例如 `git status --porcelain` 或 `pip list --format=json`。要从它们那里取数据,就意味着每次都得记住这个标志、以及解析其输出的命令。[`@structured`](/commands/docs/attr_structured.md) 属性把这两样都放进 `extern` 声明里,所以你只需写一次: + +```nu +@structured [--porcelain] { lines | parse --regex '^(?..) (?.+)$' } +extern "git status" [] +``` + +`@structured` 接受两个参数: + +- 一个参数列表,用于让该命令输出机器可读的结果。列表中的每一项就是一个参数,所以 `[--porcelain]` 会加一个参数,而 `[-o json]` 会加两个,即 `-o` 和 `json`。若某项包含空格或 `|`,请给它加引号,否则 Nushell 会把它拆成若干项。 +- 一个把该输出转换为数据的块。这个块以 `$in` 接收命令的输出。 + +有了这个声明,单独运行 `git status` 时它仍会打印 git 惯常的文本: + +```nu +git status +# => On branch main +# => Changes to be committed: +# => (use "git restore --staged ..." to unstage) +# => new file: INSTALL.md +# => +# => Changes not staged for commit: +# => (use "git add ..." to update what will be committed) +# => (use "git restore ..." to discard changes in working directory) +# => modified: README.md +# => +# => Untracked files: +# => (use "git add ..." to include in what will be committed) +# => notes.txt +``` + +把它用管道传给一个 Nushell 命令,Nushell 就会改为运行 `git status --porcelain`,并把输出交给那个块处理。你得到的是一张表格: + +```nu +git status | where status =~ M +# => ╭───┬────────┬───────────╮ +# => │ # │ status │ file │ +# => ├───┼────────┼───────────┤ +# => │ 0 │ M │ README.md │ +# => ╰───┴────────┴───────────╯ +``` + +你不需要用过滤器才能得到表格。当你想要全部数据时,把该命令用管道传给 [`collect`](/commands/docs/collect.md)。它是一个内部命令,因此输出会被解码,而它会原样把输入传下去: + +```nu +git status | collect +# => ╭───┬────────┬────────────╮ +# => │ # │ status │ file │ +# => ├───┼────────┼────────────┤ +# => │ 0 │ A │ INSTALL.md │ +# => │ 1 │ M │ README.md │ +# => │ 2 │ ?? │ notes.txt │ +# => ╰───┴────────┴────────────╯ +``` + +把输出保存到变量中同样会解码: + +```nu +let changes = git status +$changes | get file +# => ╭───┬────────────╮ +# => │ 0 │ INSTALL.md │ +# => │ 1 │ README.md │ +# => │ 2 │ notes.txt │ +# => ╰───┴────────────╯ +``` + +当命令能输出 JSON 时,那个块只需要 [`from json`](/commands/docs/from_json.md): + +```nu +@structured [--format=json] { from json } +extern "pip list" [] + +pip list | first 3 +# => ╭───┬───────────┬─────────╮ +# => │ # │ name │ version │ +# => ├───┼───────────┼─────────┤ +# => │ 0 │ contourpy │ 1.4.0 │ +# => │ 1 │ cycler │ 0.12.1 │ +# => │ 2 │ fonttools │ 4.66.1 │ +# => ╰───┴───────────┴─────────╯ +``` + +### Nushell 何时解码输出 + +Nushell 依据 extern 的输出流向来决定。当输出由 Nushell 自己使用时,它会加上 `@structured` 的参数并运行那个块: + +- 用管道传给内部命令:`git status | where status =~ M`,或者用 `git status | collect` 获取全部数据 +- 保存到变量中:`let changes = git status` +- 在子表达式中使用:`(git status).file` + +在其它所有情况下,命令都完全按你输入的方式运行。这包括输出流向: + +- 终端:`git status` +- 经过 `print`:`git status | print` +- 文件:`git status o> status.txt` 或 `git status | save status.txt` +- 进入 `complete`、`tee` 或 `ignore`:`git status | complete` +- 进入另一个外部命令或 `run-external`:`git status | ^less` +- 与 stderr 进入同一管道:`git status o+e>| str trim` + +当 extern 是自定义命令或 `do` 块的最后一条命令时,规则相同。在 `def gs [] { git status }` 之后,运行 `gs` 会打印 git 的文本,而 `gs | length` 返回 `3`,即有变动的文件数。 + +::: tip +每个内部命令都算数,包括处理文本的命令。`git status | lines` 是把解码后的表格传给 `lines`,而不是 git 的文本。要拿到文本,请用脱字符号调用该命令,这样它总是按原样运行: + +```nu +^git status | lines | first 1 +# => ╭───┬────────────────╮ +# => │ 0 │ On branch main │ +# => ╰───┴────────────────╯ +``` + +::: + +### 添加你自己的参数 + +Nushell 会把 `@structured` 的参数放在命令名之后、你输入的所有参数之前。下面这个 extern 为 `git log` 指定了一种容易拆分成列的输出格式: + +```nu +@structured ["--format=%h|%an|%s"] { lines | split column "|" hash author subject } +extern "git log" [] + +git log | where author == "Ana Silva" +# => ╭───┬─────────┬───────────┬──────────────────╮ +# => │ # │ hash │ author │ subject │ +# => ├───┼─────────┼───────────┼──────────────────┤ +# => │ 0 │ 73e9a8f │ Ana Silva │ Print a greeting │ +# => │ 1 │ 83c0a31 │ Ana Silva │ Initial commit │ +# => ╰───┴─────────┴───────────┴──────────────────╯ +``` + +`git log -n 2 | where author == "Ana Silva"` 实际运行的是 `git log --format=%h|%an|%s -n 2`。 + +由于你的参数排在最后,改变输出格式的标志会覆盖 `@structured` 里的那个。这样块就会收到它不是为之编写的输出。这里 `--oneline` 胜出,因此每一行整行都落进了 `hash` 列: + +```nu +git log --oneline -n 1 | first +# => ╭──────┬──────────────────────────╮ +# => │ hash │ 73e9a8f Print a greeting │ +# => ╰──────┴──────────────────────────╯ +``` + +若要使用别的格式,请用脱字符号调用该命令,例如 `^git log --oneline`。 + +### 关于 `@structured` 的更多内容 + +- 这个块可以读取 `$env`、常量以及在 `extern` 之前定义的 `let` 变量,就像 `def` 的函数体一样。它不能使用 `mut` 变量。 +- `@structured` 只对 `extern` 有效。把它放在 `def` 上会导致解析错误。 +- 如果一个 `extern` 有多个 `@structured`,Nushell 使用最后一个。 +- 当命令失败时,其错误信息会被打印。接下来发生什么取决于那个块。会读取全部输出的块(例如 `from json`)会以非零退出码的错误中断管道,该错误指向调用处。以流式读取输出的块(例如 `lines`)会把命令打印的内容继续传下去,且不引发错误。 + +`@structured` 也可以与 `export extern` 配合使用,这样模块就能共享这些声明: + +```nu +module git-data { + @structured [--porcelain] { lines | parse --regex '^(?..) (?.+)$' } + export extern "git status" [] +} +use git-data "git status" +``` + ## 局限性 -目前的`extern`语法有一些限制。在 Nushell 中,标志和位置参数是非常灵活的:标志可以在位置参数之前, 也可以与位置参数混合, 还可以跟随位置参数。许多外部命令没有这种灵活性。目前还没有一种方法来确保标志和位置参数的特定顺序与外部命令所要求的风格保持一致。 +目前的`extern`语法有一些限制。在 Nushell 中,标志和位置参数是非常灵活的:标志可以在位置参数之前,也可以与位置参数混合,还可以跟随位置参数。许多外部命令没有这种灵活性。目前还没有一种方法来确保标志和位置参数的特定顺序与外部命令所要求的风格保持一致。 -第二个限制是,有些外部命令要求使用`=`来传递标志和值。在 Nushell 中,`=`是一种方便的可选默认参数语法,目前还没有办法按要求使用它。 +第二个限制是,有些外部命令要求使用`=`来传递标志和值。在 Nushell 中,`=` 是一种方便的可选语法,目前还没有办法强制要求使用它。 此外,通过脱字符号(例如 `^ssh`)调用的外部命令不会被 `extern` 识别。 diff --git a/zh-CN/book/metadata.md b/zh-CN/book/metadata.md index 086b217399b..f3f93288f07 100644 --- a/zh-CN/book/metadata.md +++ b/zh-CN/book/metadata.md @@ -1,39 +1,169 @@ # 元数据 -在使用 Nu 的过程中,你可能遇到过这样的情况:你觉得有一些额外的事情在幕后进行。例如,假设你试图打开一个 Nu 支持的文件,但却忘记了它已被 Nu 支持并试图再次转换: +在使用 Nu 的过程中,你可能遇到过这样的情况:你觉得有一些额外的事情在幕后进行。例如,假设你试图打开一个 Nu 支持的文件,却忘记了这一点并试图再次转换: ```nu open Cargo.toml | from toml -# => error: Expected a string from pipeline -# => - shell:1:18 -# => 1 | open Cargo.toml | from toml -# => | ^^^^^^^^^ requires string input -# => - shell:1:5 -# => 1 | open Cargo.toml | from toml -# => | ---------- object originates from here +# => Error: nu::shell::only_supports_this_input_type +# => +# => × Input type not supported. +# => ╭─[repl_entry #1:1:1] +# => 1 │ open Cargo.toml | from toml +# => · ──┬─ ────┬──── +# => · │ ╰── only string input data is supported +# => · ╰── input type: record> +# => ╰──── ``` 这个错误信息不仅告诉我们,我们给 [`from toml`](/commands/docs/from_toml.md) 的不是一个字符串,还告诉我们这个值最初来自哪里。那么它是如何知道的呢? -在 Nu 中流经管道的值通常有一些额外信息,或元数据,附加在它们身上。这些通常被称为标签,就像商店里商品上的标签一样。这些标签并不影响数据,但它们给了 Nu 一种方法来改善使用这些数据的体验。 +在 Nu 中流经管道的值通常带有一些额外信息,或者说元数据。它们被称为标签,就像商店里商品上的标签一样。这些标签并不影响数据,但它们给了 Nu 一种改善数据处理体验的方式。 -让我们再次运行[`open`](/commands/docs/open.md)命令,但这一次,我们将看一下它所反馈的标签: +让我们再次运行 [`open`](/commands/docs/open.md) 命令,但这一次,我们将看一下它所反馈的标签: ```nu metadata (open Cargo.toml) -# => ╭──────┬───────────────────╮ -# => │ span │ {record 2 fields} │ -# => ╰──────┴───────────────────╯ +# => ╭──────┬────────────────────╮ +# => │ │ ╭───────┬────────╮ │ +# => │ span │ │ start │ 169459 │ │ +# => │ │ │ end │ 169463 │ │ +# => │ │ ╰───────┴────────╯ │ +# => ╰──────┴────────────────────╯ ``` -目前,我们只追踪值来自何处的起止范围(span)。让我们进一步仔细看看: +每个值都带有一个跨度,它记录了这个值在源代码中的来源位置。让我们仔细看一下: ```nu metadata (open Cargo.toml) | get span # => ╭───────┬────────╮ -# => │ start │ 212970 │ -# => │ end │ 212987 │ +# => │ start │ 169485 │ +# => │ end │ 169489 │ # => ╰───────┴────────╯ ``` -这里的范围 "start" 和 "end" 指的是下划线将标记在行中的位置。如果你数到 5,然后再数到 15,就会看到它与 "Cargo.toml" 文件名一致。这就是我们之前看到的错误是如何知道在何处标注下划线的。 +跨度的“start”和“end”是 Nushell 在当前会话中读取过的所有代码(标准库、你的配置文件,以及你输入的每条命令行)中的字节偏移量,所以这些数字才会这么大。[`view span`](/commands/docs/view_span.md) 命令可以显示某个跨度所指向的代码: + +```nu +let span = (metadata (open Cargo.toml)).span +view span $span.start $span.end +# => open +``` + +这个跨度指向产生该值的 `open` 命令。这就是我们前面看到的错误知道该在哪里画下划线的原因。 + +当你把一个命令的输出通过管道传给 [`metadata`](/commands/docs/metadata.md)、而不是作为参数传入时,你还可以看到该命令附加在其输出上的元数据。例如,`open` 会记录数据来自哪个文件: + +```nu +open Cargo.toml | metadata +# => ╭────────┬───────────────────────────────╮ +# => │ │ ╭───────┬────────╮ │ +# => │ span │ │ start │ 169587 │ │ +# => │ │ │ end │ 169591 │ │ +# => │ │ ╰───────┴────────╯ │ +# => │ source │ /home/user/project/Cargo.toml │ +# => ╰────────┴───────────────────────────────╯ +``` + +其它命令会附加其它元数据。例如,[`to json`](/commands/docs/to_json.md) 以及其它 `to` 命令会设置 `content_type`(如 `application/json`),[`ls`](/commands/docs/ls.md) 会把它的 `name` 列标记为包含[路径](#路径列),而 HTTP 命令会附加 [HTTP 响应](#http-响应元数据)。 + +这两种形式不能混用。当给 `metadata` 传入一个参数时,它只返回该参数的 `span`,并忽略任何管道输入。这使得它在闭包或块中可以安全使用,因为其中的第一条命令会接收该块的输入: + +```nu +[1 2] | each {|x| (metadata $x).span } | to nuon +# => [[start, end]; [170379, 170380], [170381, 170382]] +``` + +这也意味着 `metadata $in` 只会报告一个跨度。要查看随管道输入而来的元数据,例如 `source` 或 `content_type`,请使用不带参数的 `metadata`。 + +## 自定义元数据 + +你可以使用 [`metadata set`](/commands/docs/metadata_set.md) 命令及其可选的闭包参数,把任意元数据附加到管道数据上: + +```nu +"data" | metadata set { merge {custom_key: "custom_value"} } | metadata +# => ╭────────────┬────────────────────╮ +# => │ │ ╭───────┬────────╮ │ +# => │ span │ │ start │ 169613 │ │ +# => │ │ │ end │ 169619 │ │ +# => │ │ ╰───────┴────────╯ │ +# => │ custom_key │ custom_value │ +# => ╰────────────┴────────────────────╯ +``` + +## 路径列 + +列出文件的命令,例如 [`ls`](/commands/docs/ls.md),会标记出包含路径的列: + +```nu +ls | metadata +# => ╭──────────────────────────────┬────────────────────╮ +# => │ │ ╭───────┬────────╮ │ +# => │ span │ │ start │ 169684 │ │ +# => │ │ │ end │ 169686 │ │ +# => │ │ ╰───────┴────────╯ │ +# => │ │ ╭───┬──────╮ │ +# => │ path_columns │ │ 0 │ name │ │ +# => │ │ ╰───┴──────╯ │ +# => │ │ ╭───┬──────╮ │ +# => │ table_width_priority_columns │ │ 0 │ name │ │ +# => │ │ ╰───┴──────╯ │ +# => ╰──────────────────────────────┴────────────────────╯ +``` + +当 [`table`](/commands/docs/table.md) 显示 `path_columns` 中列出的某一列时,它会根据 `$env.LS_COLORS` 为路径着色,而 `table --icons` 还会为每种文件类型添加一个图标。`table_width_priority_columns` 列表告诉 `table`,当表格对于终端来说过宽时,应该优先把空间分给哪些列。 + +你也可以用 `metadata set` 在自己的数据上设置这两项: + +```nu +[[name size]; [Cargo.toml 1.2kB]] +| metadata set --path-columns [name] --table-width-priority-columns [name] +| metadata +| reject span +# => ╭──────────────────────────────┬──────────────╮ +# => │ │ ╭───┬──────╮ │ +# => │ path_columns │ │ 0 │ name │ │ +# => │ │ ╰───┴──────╯ │ +# => │ │ ╭───┬──────╮ │ +# => │ table_width_priority_columns │ │ 0 │ name │ │ +# => │ │ ╰───┴──────╯ │ +# => ╰──────────────────────────────┴──────────────╯ +``` + +## 在管道中使用元数据 + +[`metadata access`](/commands/docs/metadata_access.md) 会用其输入的元数据运行一个闭包,而数据本身仍可通过 `$in` 获得: + +```nu +{foo: bar} | to json --raw | metadata access {|meta| {in: $in, content: $meta.content_type}} +# => ╭─────────┬──────────────────╮ +# => │ in │ {"foo":"bar"} │ +# => │ content │ application/json │ +# => ╰─────────┴──────────────────╯ +``` + +## 窥探流 + +[`peek`](/commands/docs/peek.md) 会把流的前几个元素存进它的元数据里,这样你无需收集整个流就能查看它们: + +```nu +seq 1 5 | peek 2 | metadata | get peek +# => ╭────────┬───────────╮ +# => │ type │ list │ +# => │ stream │ true │ +# => │ │ ╭───┬───╮ │ +# => │ value │ │ 0 │ 1 │ │ +# => │ │ │ 1 │ 2 │ │ +# => │ │ ╰───┴───╯ │ +# => ╰────────┴───────────╯ +``` + +## HTTP 响应元数据 + +所有 HTTP 命令都会附加响应元数据: + +```nu +http get https://example.com | metadata | get http_response.status +# => 200 +``` + +关于在流式传输响应体时处理元数据,请参阅 [HTTP 实用手册](../cookbook/http.md)。 diff --git a/zh-CN/book/running_externals.md b/zh-CN/book/running_externals.md index 20b3171abcd..80b8d85771f 100644 --- a/zh-CN/book/running_externals.md +++ b/zh-CN/book/running_externals.md @@ -1,6 +1,6 @@ # 运行系统(外部)命令 -Nu提供了一组可以在不同操作系统上使用的命令("内部"命令),这种一致性在创建跨平台代码时很有帮助。但有时,你可能想运行一个与Nu内部命令同名的外部命令。例如,要运行外部的[`ls`](/commands/docs/ls.md)或[`date`](/commands/docs/date.md)命令,可以在前面加上脱字符(^)。使用脱字符前缀会调用用户`PATH`中找到的外部命令(例如`/bin/ls`),而不是Nu内部的[`ls`](/commands/docs/ls.md)命令。 +Nu提供了一组可以在不同操作系统上使用的命令("内部"命令),这种一致性在创建跨平台代码时很有帮助。但有时,你可能想运行一个与Nu内部命令同名的外部命令。例如,要运行外部的[`ls`](/commands/docs/ls.md)或[`date`](/commands/docs/date.md)命令,可以在前面加上脱字符号(^)。使用脱字符号前缀会调用用户`PATH`中找到的外部命令(例如`/bin/ls`),而不是Nu内部的[`ls`](/commands/docs/ls.md)命令。 Nu内部命令: @@ -18,7 +18,62 @@ ls 在Windows上,`ls`默认是PowerShell的 _别名_,因此`^ls`不会找到匹配的系统 _命令_。 ::: -## Windows额外说明 +## 用 `%` 运行内置命令 + +百分号(`%`)符号的作用与脱字符号相反:它总是运行 Nushell 的内置命令,即使存在同名的自定义命令或别名把它遮蔽了: + +```nu +def echo [...args] { "custom echo" } +echo hello +# => custom echo +%echo hello +# => hello +``` + +`%` 调用只会解析到内置命令。它仍然能找到被 [`hide`](/commands/docs/hide.md) 隐藏的内置命令,并且绝不会回退到外部命令或自定义命令。如果没有同名的内置命令,Nushell 会报错: + +```nu +%lss +# => Error: nu::parser::error +# => +# => × percent sigil requires a built-in command +# => ╭─[repl_entry #1:1:2] +# => 1 │ %lss +# => · ─┬─ +# => · ╰── unknown built-in command +# => ╰──── +# => help: remove `%` to use normal resolution, or use `^` to run an external command explicitly +``` + +与 `^` 一样,`%` 符号也接受存放在变量里的命令名,例如 `%$cmd`。 + +## 传递参数 + +外部参数由 Nushell 语法分隔,而不是由带引号的字符串里的空格分隔。给字符串加引号可以把其中的空格保留在同一个参数内: + +```nu +git commit -m "Update external command documentation" +``` + +Nushell 不会自动把列表转换为外部参数,直接传入列表会产生错误。请使用展开运算符(`...`)把列表的每个元素作为独立参数传入: + +```nu +let paths = ["file one.txt" "file two.txt"] +git add ...$paths +``` + +这里 `git` 会收到两个路径参数,每个路径中的空格仍然是该参数的一部分。更多示例和完整的展开规则,请参阅[命令调用中的展开运算符](operators.md#在命令调用中)。 + +脱字符号也可以运行名称或路径存放在变量中的可执行文件: + +```nu +let program = "git" +^$program status +``` + +关于支持的字符串形式,请参阅[字符串作为外部命令](working_with_strings.md#字符串作为外部命令)。[`extern` 声明](externs.md)可以为已知的外部命令添加类型检查和补全,其 [`@structured`](externs.md#结构化输出) 属性还能把命令的输出转换为数据。调用它时同样遵循这里描述的参数规则。 + +## Windows 额外说明 在Windows上运行外部命令时, Nushell会将一些`CMD.EXE`内部命令转发给cmd,而不是尝试运行外部命令。 diff --git a/zh-CN/book/scripts.md b/zh-CN/book/scripts.md index 5685f5094b7..851985e3c12 100644 --- a/zh-CN/book/scripts.md +++ b/zh-CN/book/scripts.md @@ -1,21 +1,23 @@ # 脚本 -在 Nushell 中,你可以用 Nushell 语言编写和运行脚本。要运行一个脚本,你可以把它作为一个参数传递给`nu`命令行程序: +在 Nushell 中,你可以用 Nushell 语言编写并运行脚本。要运行一个脚本,可以把它作为参数传递给 `nu` 命令行程序: ```nu nu myscript.nu ``` -这将在一个新的 Nu 实例中运行脚本直至完成。你也可以使用[`source`](/commands/docs/source.md)在 Nu 的 **当前** 实例中运行脚本: +这会在一个新的 Nu 实例中运行脚本直至完成。你也可以使用 [`source`](/commands/docs/source.md) 在**当前**的 Nu 实例中运行脚本: ```nu source myscript.nu ``` -我们来看一个脚本文件的例子吧: +要把脚本用作管道中的一个阶段,请使用 [`run`](/commands/docs/run.md),参见下文的[管道中的脚本](#管道中的脚本)。 + +我们来看一个脚本文件的例子: ```nu -# myscript.nu +# hello.nu def greet [name] { ["hello" $name] } @@ -23,9 +25,9 @@ def greet [name] { greet "world" ``` -脚本文件包含了自定义命令的定义以及主脚本本身,它将在自定义命令定义后运行。 +脚本文件既定义了自定义命令,也包含了主脚本本身,后者会在自定义命令定义完成之后运行。 -在上面的例子中,首先`greet`是由 Nushell 解释器定义的,这使得我们之后可以调用这个定义,我们可以把上面的内容写成: +在上面的例子中,首先 `greet` 由 Nushell 解释器定义,这样我们之后就可以调用这个定义。我们也可以把上面写成: ```nu greet "world" @@ -35,46 +37,52 @@ def greet [name] { } ``` -Nushell 并不要求定义必须放在脚本中调用该定义之前,你可以把定义放在你觉得舒服的地方。 +定义并不要求必须出现在脚本中调用它的部分之前,你可以把它们放在你觉得顺手的地方。 + +请记住,脚本只会显示它最后一条管道的值。在上面第二个版本中,最后一条管道是 `def`,所以 `greet` 仍然会运行,但它的结果不会被显示。要在脚本中的任意位置显示一个值,请使用 [`print`](/commands/docs/print.md)。 ## 脚本是如何被处理的 -在一个脚本中定义总是先运行,这样我们就可以在脚本中调用定义。 +在脚本中,定义先运行。这让我们可以在脚本中调用这些定义。 -在定义运行之后, 我们从脚本文件的顶部开始, 一个接一个地运行每一组命令。 +定义运行之后,我们从脚本文件的顶部开始,依次运行每一组命令。 ## 脚本行 -为了更好地理解 Nushell 是如何看待代码行的, 我们来看一个脚本的例子: +为了更好地理解 Nushell 是如何看待代码行的,我们来看一个示例脚本: ```nu -a -b; c | d +print "a" +"b"; "c" | str uppercase +# => a +# => C ``` -当这个脚本运行时,Nushell 将首先运行`a`命令至完成并查看其结果。接下来,Nushell 将按照[“分号”部分](pipelines.html#semicolons)中的规则运行`b; c | d`。 +当这个脚本运行时,Nushell 会先运行 `print "a"` 直至完成,这会打印出 `a`。接着,Nushell 会按照[“分号”部分](pipelines.md#分号)中的规则运行 `"b"; "c" | str uppercase`:值 `"b"` 被丢弃,而 `"c" | str uppercase` 是一条正常的管道。由于它是脚本的最后一条管道,其结果 `C` 会被显示出来。 ## 参数化脚本 -脚本文件可以选择性地包含一个特殊的 "main" 命令。`main`将在任何其他 Nu 代码之后运行,主要用于向脚本添加位置参数和标志。你可以在脚本名称后面传递参数(`nu