跳过正文
  1. Lumesh 文档/
  2. 语法/

语法:管道与错误

2608 字·6 分钟
目录

管道、重定向、错误、日志

九、管道与重定向
#

管道
#

  1. 管道简介

lumesh采用和bash一样的管道符,但更加强大:

  • 智能管道 | 自动判断应有行为方式,可传输结构化数据。

    • 左侧:可以自动从运算结果或标准输出读取;

      读取原则: 对于函数和内置命令、运算,读取结构化数据通道。 对于系统三方命令,读取标准输出。

    • 右侧:

      输出原则: 如果是三方命令则作为标准输入传入数据 如果是函数则作为末尾参数传递。

数据函数、运算、内置命令三方命令
输人(左侧)读取结构化数据通道读取标准输出
输出(右侧)输出到最后一个参数输出到标准输入
  • 位置管道 |_ 强制使用参数位置管道,管道到右侧函数的指定位置,以_为占位符,如果未指定,则附加到参数末尾。 多数情况下不需要手动指定。使用|足够。 但如果右侧的命令无法读取标准输入,或需要指定参数位置时,需要使用此管道。

    13 | print a _ b               # 打印结果: a 3 b
  • 循环派发管道 |> 用于将左侧列表任务,循环派发给右侧命令。 同样支持_占位符。

    1  0...8 |> print lineNo          # 将打印8行
    2  ls -1 *.txt |> cp _ /tmp/            # 将拷贝列出的文件
  • PTY管道 |^ 强制右侧命令使用PTY模式。 某些程序需要完全的终端控制权限,才能正常工作,因此需要pty模式。 智能管道维护着一个此类程序的列表,因此一般无须强制开启pty模式,但如果您发现某个程序无法正常工作,可以尝试强制开启PTY模式。

  1. 管道基础用法

传统的bash管道为了兼容更多命令,只能处理字节流。字节流是由三方命令输出的文本数据,shell通过管道派发给下一个程序处理。这种模式极大的方便了数据在不同程序之间的传输。

实际上结构化管道的效率更高,因为它省去了从普通文本转化为结构化数据的工作;甚至有的还可以省去和输入输出设备打交到的时间。

结构化管道效率更高 例如:

 1# --这是文本流管道--
 2echo 3+5 | bat              # 这是三方命令,且需要管道从标准输出读取, 效率双重降低
 3
 4# --这是结构化管道-- *推荐用法*
 53+5 | bat                   # 运算结果直接传送到下一个程序
 6
 7# --这是不正确用法--
 8print 3+5 | bat             # print语句打印到标准输出,同时传递出None作为运算结果,bat捕捉到的是print语句的运算结果None
 9
10# --这是结构化管道--
11tap 3+5 | bat               # tap语句打印到标准输出,同时将结果向下传递,bat正确捕捉到这个运算结果
123+5 | tap | bat             # 等价上一句

从上面的例子可以看出,

  • 运算结果如不需要打印,只需向下传递,应直接使用管道。
  • 运算结果如果需要打印,并向下传递,应使用tap后再管道。
  • 运算结果打印后不需要向下传递,应使用print。
  • 应避免使用echo,除非需要echo -e 等高级选项。
  1. 管道高级用法
  • 筛选

     1# 按大小筛选数据,并显示指定列:
     2Fs.ls -l | where(size > 5K) | select(name,size,modified)
     3
     4# 输出
     5+--------------------------------------+
     6| MODIFIED          NAME          SIZE |
     7+======================================+
     8| 2025-06-02 06:26  Cargo.lock    46K  |
     9| 2025-06-02 04:40  CHANGELOG.md  9K   |
    10+--------------------------------------+
  • 排序

     1# 按时间筛选数据,并按指定列排序
     2Fs.ls -l | where( Fs.diff('d',modified) > 3 ) | sort(size,name)
     3
     4# 输出
     5+-------------------------------------------------------+
     6| MODE  MODIFIED          NAME          SIZE  TYPE      |
     7+=======================================================+
     8| 511   2025-03-29 05:58  target        11    symlink   |
     9| 493   2025-04-06 12:21  benches       66    directory |
    10| 493   2025-05-13 10:57  assets        102   directory |
    11| 493   2025-03-23 11:58  target_       128   directory |
    12| 420   2025-03-23 05:32  LICENSE       1K    file      |
    13| 420   2025-05-29 12:57  README-cn.md  4K    file      |
    14| 420   2025-05-29 12:57  README.md     4K    file      |
    15+-------------------------------------------------------+
  • 分组

     1# 按类型分组
     2Fs.ls -l | group 'type'     # type是函数名,所以引号不能省略
     3
     4+-----------------------------------------------------------------+
     5| KEY        VALUE                                                |
     6+=================================================================+
     7| directory  +--------------------------------------------------+ |
     8|            | MODE  MODIFIED          NAME     SIZE  TYPE      | |
     9|            +==================================================+ |
    10|            | 493   2025-05-13 10:57  assets   102   directory | |
    11|            | 493   2025-04-06 12:21  benches  66    directory | |
    12|            | 493   2025-06-02 05:15  src      346   directory | |
    13|            | 493   2025-06-03 04:32  wiki     528   directory | |
    14|            +--------------------------------------------------+ |
    15| file       +--------------------------------------------------+ |
    16|            | MODE  MODIFIED          NAME          SIZE  TYPE | |
    17|            +==================================================+ |
    18|            | 420   2025-03-23 05:32  LICENSE       1K    file | |
    19|            | 420   2025-05-29 12:57  README.md     4K    file | |
    20|            | 420   2025-06-02 06:26  Cargo.lock    46K   file | |
    21|            | 420   2025-06-02 04:40  CHANGELOG.md  9K    file | |
    22|            | 420   2025-06-02 06:26  Cargo.toml    2K    file | |
    23|            +--------------------------------------------------+ |
    24| symlink    +-----------------------------------------------+    |
    25|            | MODE  MODIFIED          NAME    SIZE  TYPE    |    |
    26|            +===============================================+    |
    27|            | 511   2025-03-29 05:58  target  11    symlink |    |
    28|            +-----------------------------------------------+    |
    29+-----------------------------------------------------------------+
  • 兼容系统的三方命令

可以使用From.cmd 或 Into.table 或链式调用 .table(),将文本转换结构化数据。可接收列名序列作为参数。

但比较数据时,需要手动转换类型。

 1ls -l --time-style=long-iso | .table() | where(int C4>1000)
 2
 3# 输出
 4+------------------------------------------------------------------+
 5| C0          C1  C2   C3   C4     C5          C6     C7           |
 6+==================================================================+
 7| -rw-r--r--  1   tix  tix  10046  2025-06-02  12:40  CHANGELOG.md |
 8| -rw-r--r--  1   tix  tix  47312  2025-06-02  14:26  Cargo.lock   |
 9| -rw-r--r--  1   tix  tix  2226   2025-06-02  14:26  Cargo.toml   |
10| -rw-r--r--  1   tix  tix  1075   2025-03-23  13:32  LICENSE      |
11| -rw-r--r--  1   tix  tix  4180   2025-05-29  20:57  README-cn.md |
12| -rw-r--r--  1   tix  tix  4333   2025-05-29  20:57  README.md    |
13+------------------------------------------------------------------+

重定向
#

  • << 读取
  • >> 追加输出
  • >! 覆盖输出 1 + 2 >> result.txt

错误重定向:结合错误处置符 具体用法请参考 错误处理章节。

重定向类型LumeBash
标准输出,追加cmd >> out.txtcmd >> out.txt
标准输出,覆盖cmd >! out.txtcmd > out.txt
错误替代标准输出cmd ?> >> out.logcommand 2>&1 >> out.log
单独的错误输出cmd ?? >> out.logcmd 2>> out.log
合并标准输出和错误输出cmd ?+ >> out.logcmd >> out.log 2>&1

十、错误处理
#

错误捕获: ?:
#

语句后跟 ?: expr

  • 通常expr 可以是一个lambda函数,该函数可以接受一个Error对象。该Error对象是一个Map对象,可以用.@[]索引,获取具体属性。 该对象包含三个属性:

    • code
    • msg
    • expr
  • 如果expr是常规类型,则在异常时提供默认值。

错误忽略: ?.
#

相当于 ?: {}

错误打印: ?+ ?? ?>
#

  • 错误打印到标准输出: ?+ 相当于 ?: e -> echo e.msg

  • 错误打印到错误输出: ?? 相当于 ?: e -> eprint e.msg

  • 错误作为运算结果输出: ?> 相当于 ?: e -> e.msg

错误终止: ?!
#

  • 遇到错误时,静默终止管道 Fs.ls -l | ui.pick ?! |_ cp _ /tmp

当用户放弃选择时,遇错终止后续管道操作。

以上方式可以作用于任何语句或函数末尾错误处置符的优先级高于管道

 1
 26 / 0 ?.    # ignore err
 36 / 0 ?+    # print err to stdout
 46 / 0 ??    # print err to stderr
 56 / 0 ?!    # use this err msg as result
 6
 7let e = x -> echo x.code
 86 /0 ?: e   # deeling the err with a function/lambda
 9
10# also funcions could use err handling too.
11fn divide(x,y){
12    x / y
13}?: e

Tips

  • 利用错误处置符的特性,还可以为计算失败时提供默认值:

    1let e = x -> 0
    2let result = 6 /0 ?: e
    3echo result              # 输出默认值: 0
    4
    5# 等同于
    6let result = 6 /0 ?: 0
    7echo result              # 输出默认值: 0
  • 在函数定义时,使用错误处理

    1let e = x -> {print x.code}
    2
    3fn div(a,b){
    4    a / b
    5} ?: e
    6
    7div(3,0)                # the defined error handling will be executed here.

错误调试:
#

  • 错误提示 一般情况下,观察错误提示,足以发现问题所在。 如:

     1[PARSE FAILED]                        # 语法解析错误
     2unexpected syntax error: expect "{"
     3 4    1 ▏ fn assert(actual, expected, test_name, test_count=0) {
     5    2if actual != expected
     6      ▏                           ^
     7    3 ▏         print "[FAIL]" test_count test_name "| 实际:" actual "| 预期" expected
     8    4} else {
     9    5 ▏         print "[PASS]" test_count test_name
    1011      ↳ at line 2, column 27
    12
    13
    14> 0...8 x
    15[ERROR]                                # 运行时错误
    16Message   [1]: type error, expected Symbol as command, found 0...8: List
    17Expression[1]: 0...8  x
    18
    19SyntaxTree[1]:
    20Cmd 〈0...8〉
    2122  Symbol〈"x"23
  • debug 命令 如需进一步调试,可以使用debug命令。

     1# 简单数据调试:
     2let c = 0..8
     3debug c                     # 输出:Range〈0..9,1〉
     4
     5# 复杂语句调试:
     6let a := if a {3 + 5} else { print a is False}
     7debug a
     8
     9# 输出:
    10if (Symbol〈"a") {
    11
    12  {
    13
    14      Integer〈3〉
    15      +
    16      Integer〈5〉
    17  }
    18
    19}else{
    20
    21  {
    22
    23    Cmd 〈Symbol〈"print"〉〉
    2425      Symbol〈"a"26      Symbol〈"is"27      Boolean〈false〉
    2829
    30  }
    31
    32}
  • Log 模块 Log模块的使用也有利于错误调试,具体请参考Log模块文档

相关文章