mcpField
N
nushell-usage

nushell-usage

github.com/ypares开发3061 次安装今天更新
代码仓库

关于 nushell-usage

nushell-usage 是面向 Nushell 用户的用法参考技能,汇集管道、闭包、类型签名和数据操作等模式。它特别说明容易混淆的输入语义与常见陷阱,帮助编写和调试 Nushell 代码。

主要功能

  1. 01区分管道输入与函数参数
  2. 02展示列表、记录和表格操作
  3. 03说明条件、闭包与迭代模式
  4. 04处理可空字段和错误
  5. 05整理模块、类型签名与调试实践

适用场景

  1. 01编写带管道签名的 Nushell 函数
  2. 02选择行条件或闭包处理表格
  3. 03排查字段缺失及闭包变量捕获问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ypares/agent-skills --skill nushell-usage

安装后在 Claude Code 中输入/nushell-usage确认已加载。

附带文件references/advanced-patterns.mdreferences/type-system.md

详细介绍

Nushell 使用模式

关键区别

管道输入与参数

重要:管道输入($in)不能与函数参数互换!

# ❌ WRONG - treats $in as first parameter
def my-func [list: list, value: any] {
    $list | append $value
}

# ✅ CORRECT - declares pipeline signature
def my-func [value: any]: list -> list {
    $in | append $value
}

# Usage
[1 2 3] | my-func 4  # Works correctly
my-func [1 2 3] 4    # ERROR! my-func doesn't take positional params

闭包也适用。

这很重要,因为:

  • 管道输入可以惰性求值(流式处理)
  • 参数会立即求值(加载到内存中)
  • 两者的调用约定完全不同
类型签名
# No pipeline input
def func [x: int] { ... }                    # (x) -> output

# Pipeline input only
def func []: string -> int { ... }           # string | func -> int

# Both pipeline and parameters
def func [x: int]: string -> int { ... }     # string | func x -> int

# Generic pipeline
def func []: any -> any { ... }              # works with any input type

常见模式

处理列表
# Filter with index
$list | enumerate | where {|e| $e.index > 5 and $e.item.some-bool-field}

# Transform with previous state
$list | reduce --fold 0 {|item, acc| $acc + $item.value}
处理记录
# Create record
{name: "Alice", age: 30}

# Merge records (right-biased)
$rec1 | merge $rec2

# Merge many records (right-biased)
[$rec1 $rec2 $rec3 $rec4] | into record

# Update field
$rec | update name {|r| $"Dr. ($r.name)"}

# Insert field
$rec | insert active true

# Insert field based on existing fields
{x:1, y: 2} | insert z {|r| $r.x + $r.y}

# Upsert (update or insert)
$rec | upsert count {|r| ($r.count? | default 0) + 1}

# Reject fields
$rec | reject password secret_key

# Select fields
$rec | select name age email
处理表格
# Tables are lists of records
let table = [
    {name: "Alice", age: 30}
    {name: "Bob", age: 25}
]

# Filter rows
$table | where age > 25

# Add column
$table | insert retired {|row| $row.age > 65}

# Rename column
$table | rename -c {age: years}

# Group by
$table | group-by status --to-table

# Transpose (rows ↔ columns)
$table | transpose name data
条件执行
# If expressions return values
let result = if $condition {
    "yes"
} else {
    "no"
}

# Match expressions
let result = match $value {
    0 => "zero"
    1..10 => "small"
    _ => "large"
}
空值安全
# Optional fields with ?
$record.field?                    # Returns null if missing
$record.field? | default "N/A"    # Provide fallback

# Check existence
if ($record.field? != null) { ... }
错误处理
# Try-catch
try {
    dangerous-operation
} catch {|err|
    print $"Error: ($err.msg)"
}

# Returning errors
def my-func [] {
    if $condition {
        error make {msg: "Something went wrong"}
    } else {
        "success"
    }
}

# Check command success
let result = try { fallible-command }
if ($result == null) {
    # Handle error
}

# Use complete for detailed error info for EXTERNAL commands (bins)
let result = (fallible-external-command | complete)
if $result.exit_code != 0 {
    print $"Error: ($result.stderr)"
}
闭包与作用域
# Closures capture environment
let multiplier = 10
let double_and_add = {|x| ($x * 2) + $multiplier}
5 | do $double_and_add  # Returns 20

# Outer mutable variables CANNOT be captured in closures
mut sum = 0
[1 2 3] | each {|x| $sum = $sum + $x}  # ❌ WON'T COMPILE

# Use reduce instead
let sum = [1 2 3] | reduce {|x, acc| $acc + $x}
迭代模式
# each: transform each element
$list | each {|item| $item * 2}

# each --flatten: stream outputs instead of collecting
# Turns list<list<T>> into list<T> by streaming items as they arrive
ls *.txt | each --flatten {|f| open $f.name | lines } | find "TODO"

# each --keep-empty: preserve null results
[1 2 3] | each --keep-empty {|e| if $e == 2 { "found" }}
# Result: ["" "found" ""]  (vs. without flag: ["found"])

# filter/where: select elements
# Row condition (field access auto-uses $it)
$table | where size > 100        # Implicit: $it.size > 100
$table | where type == "file"    # Implicit: $it.type == "file"

# Closure (must use $in or parameter)
$list | where {|x| $x > 10}
$list | where {$in > 10}         # Same as above

# reduce/fold: accumulate
$list | reduce --fold 0 {|item, acc| $acc + $item}

# Reduce without fold (first element is initial accumulator)
[1 2 3 4] | reduce {|it, acc| $acc - $it}  # ((1-2)-3)-4 = -8

# par-each: parallel processing
$large_list | par-each {|item| expensive-operation $item}

# for loop (imperative style)
for item in $list {
    print $item
}
字符串操作
# Interpolation
$"Hello ($name)!"
$"Sum: (1 + 2)"  # "Sum: 3"

# Split/join
"a,b,c" | split row ","        # ["a", "b", "c"]
["a", "b"] | str join ", "     # "a, b"

# Regex
"hello123" | parse --regex '(?P<word>\w+)(?P<num>\d+)'

# Multi-line strings
$"
Line 1
Line 2
"
Glob 模式(文件匹配)
# Basic patterns
glob *.rs                         # All .rs files in current dir
glob **/*.rs                      # Recursive .rs files
glob **/*.{rs,toml}               # Multiple extensions

注意:搜索文件时,优先使用 glob,而不是 find 或 ls——它效率更高,模式支持也更好。

模块系统
# Define module
module my_module {
    export def public-func [] { ... }
    def private-func [] { ... }

    export const MY_CONST = 42
}

# Use module
use my_module *
use my_module [public-func MY_CONST]

# Import from file
use lib/helpers.nu *

行条件与闭包

许多命令既接受行条件,也接受闭包:

行条件(简写语法)
# Automatic $it expansion on left side
$table | where size > 100           # Expands to: $it.size > 100
$table | where name =~ "test"       # Expands to: $it.name =~ "test"

# Works with: where, filter (DEPRECATED, use where), find, skip while, take while, etc.
ls | where type == file             # Simple and readable

限制:

  • 不能存储在变量中
  • 只有左侧的字段访问会自动展开
  • 子表达式需要显式使用 $it:
    ls | where ($it.name | str downcase) =~ readme  # Need $it here
    
闭包(完全灵活)
# Use $in or parameter name
$table | where {|row| $row.size > 100}
$table | where {$in.size > 100}

# Can be stored and reused
let big_files = {|row| $row.size > 1mb}
ls | where $big_files

# Works anywhere
$list | each {|x| $x * 2}
$list | where {$in > 10}

适用场景:

  • 行条件:简单的字段比较(语法更简洁)
  • 闭包:复杂逻辑、可复用条件、嵌套操作

常见陷阱

对单条记录使用 each
# ❌ Don't pass single records to each
let record = {a: 1, b: 2}
$record | each {|field| print $field}  # Only runs once!

# ✅ Use items, values, or transpose instead
$record | items {|key, val| print $"($key): ($val)"}
$record | transpose key val | each {|row| ...}
管道与调用的歧义
# These are different!
$list | my-func arg1 arg2   # $list piped, arg1 & arg2 as params
my-func $list arg1 arg2     # All three as positional params (if signature allows)
可选字段
# ❌ Error if field doesn't exist
$record.missing  # ERROR

# ✅ Use ?
$record.missing?  # null
$record.missing? | default "N/A"  # "N/A"
空集合
# Empty list/table checks
if ($list | is-empty) { ... }

# Default value if empty
$list | default -e $val_if_empty

高级主题

有关高级模式和深入讲解,请参阅:

最佳实践

  1. 使用类型签名 - 有助于及早发现错误
  2. 优先使用管道 - 更符合惯用写法,也更易组合
  3. 用注释编写文档 - 行内注释使用 #,声明上方也可使用 # 编写文档注释
  4. 有选择地导出 - 避免污染命名空间
  5. 使用 default - 妥善处理空值或缺失值
  6. 验证输入 - 在函数开头检查类型和范围
  7. 返回一致的类型 - 不要意外混用空值和其他值
  8. 使用模块 - 组织相关函数
  9. 逐步测试 - 一步步构建复杂管道
  10. 给外部命令加上脱字符前缀 - 使用 ^grep,而不只是 grep。这样可以明确它不是 Nushell 命令,避免歧义。Nushell 命令始终优先,例如 find 不是通常的 Unix find 工具:请使用 ^find。
  11. 需要时使用专用外部命令 - 搜索大量文件时,grep 或 rg 仍然更快;处理大型嵌套 JSON 结构时,jq 也快得多

调试技巧

# Print intermediate values
$data | each {|x| print $x; $x}  # Prints and passes through

# Inspect type
$value | describe

# Debug point
debug           # Drops into debugger (if available)

# Timing
timeit { expensive-command }

外部资源

评论

支持 Markdown