Skip to main content
  1. Lumesh Document/
  2. Lumesh Syntax/

Pipes and Errors

1881 words·4 mins
Table of Contents

Pipes, Redirection, Errors, Logs

IX. Pipes and Redirection
#

Pipes
#

  1. Introduction to Pipes

Lumesh uses the same pipe symbol as bash, but it is more powerful:

  • Smart Pipe | Automatically determines the appropriate behavior and can transmit structured data.

    • Left Side: Can automatically read from the result of operations or standard output;

      Reading Principle: For functions, built-in commands, and operations, read from the structured data channel. For third-party system commands, read from standard output.

    • Right Side:

      Output Principle: If it is a third-party command, the data is passed as standard input. If it is a function, the data is passed as the last parameter.

DataFunctions, Operations, Built-in CommandsThird-party Commands
Input (Left)Reads from the structured data channelReads from standard output
Output (Right)Outputs to the last parameterOutputs to standard input
  • Position Pipe |_ Forces the use of positional parameters in the pipe, directing the pipe to a specified position in the right-side function, using _ as a placeholder. If not specified, it appends to the end of the parameters. In most cases, manual specification is unnecessary. Using | is sufficient. However, if the right-side command cannot read standard input or requires specified parameter positions, this pipe must be used.

    13 | print a _ b               # Prints result: a 3 b
  • Loop Dispatch Pipe |> Used to loop dispatch tasks from the left-side list to the right-side command. Also supports _ placeholders.

    1  0...8 |> print lineNo          # Will print 8 lines
    2  ls -1 *.txt |> cp _ /tmp/      # Will copy the listed files
  • PTY Pipe |^ Forces the right-side command to use PTY mode. Some programs require complete terminal control permissions to function correctly, thus requiring PTY mode. The smart pipe maintains a list of such programs, so generally, there is no need to force PTY mode, but if you find a program not functioning correctly, you can try forcing PTY mode.

  1. Basic Usage of Pipes

Traditional bash pipes, to maintain compatibility with more commands, can only handle byte streams. Byte streams are text data output by third-party commands, which the shell dispatches to the next program for processing. This mode greatly facilitates data transmission between different programs.

In fact, structured pipes are more efficient because they eliminate the need to convert plain text into structured data; some can even save time interacting with input/output devices.

Structured Pipes are More Efficient For example:

 1# -- This is a text stream pipe --
 2echo 3+5 | bat              # This is a third-party command, and requires the pipe to read from standard output, resulting in double inefficiency
 3
 4# -- This is a structured pipe -- *Recommended usage*
 53+5 | bat                   # The operation result is directly sent to the next program
 6
 7# -- This is incorrect usage --
 8print 3+5 | bat             # The print statement outputs to standard output, while also passing None as the operation result; bat captures the None result from the print statement
 9
10# -- This is a structured pipe --
11tap 3+5 | bat               # The tap statement prints to standard output while passing the result down, bat correctly captures this operation result
123+5 | tap | bat             # Equivalent to the previous statement

From the examples above, we can see:

  • If the operation result does not need to be printed and only needs to be passed down, use the pipe directly.
  • If the operation result needs to be printed and passed down, use tap before the pipe.
  • If the operation result is printed and does not need to be passed down, use print.
  • Avoid using echo unless advanced options like echo -e are needed.
  1. Advanced Usage of Pipes
  • Filtering

     1# Filter data by size and display specified columns:
     2Fs.ls -l | where(size > 5K) | select(name,size,modified)
     3
     4# Output
     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+--------------------------------------+
  • Sorting

     1# Filter data by time and sort by specified columns
     2Fs.ls -l | where( Fs.diff('d',modified) > 3 ) | sort(size,name)
     3
     4# Output
     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+-------------------------------------------------------+
  • Grouping

     1# Group by type
     2Fs.ls -l | group 'type'     # type is a function name, so the quotes cannot be omitted
     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+-----------------------------------------------------------------+
  • Compatible with Third-party System Commands

You can use From.cmd or Into.table or chained calls .table() to convert text into structured data. It can accept a sequence of column names as parameters.

However, when comparing data, you need to manually convert types.

 1ls -l --time-style=long-iso | .table() | where(int C4>1000)
 2
 3# Output
 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+------------------------------------------------------------------+

Redirection
#

  • << Read
  • >> Append Output
  • >! Overwrite Output 1 + 2 >> result.txt

Error Redirection: Combined with Error Handling Symbols For specific usage, please refer to the error handling section.

Redirection TypeLumeBash
Standard Output, Appendcmd >> out.txtcmd >> out.txt
Standard Output, Overwritecmd >! out.txtcmd > out.txt
Error Redirect to Standard Outputcmd ?> >> out.logcommand 2>&1 >> out.log
Separate Error Outputcmd ?? >> out.logcmd 2>> out.log
Merge Standard and Error Outputcmd ?+ >> out.logcmd >> out.log 2>&1

X. Error Handling
#

Error Capture: ?:
#

A statement followed by ?: expr,

  • Typically, expr can be a lambda function that accepts an Error object. This Error object is a Map object, and you can index specific properties using . or @ or []. This object contains three properties:

    • code
    • msg
    • expr
  • If expr is of a regular type, it provides a default value in case of an exception.

Error Ignoring: ?.
#

Equivalent to ?: {}

Error Printing: ?+, ??, ?>
#

  • Print error to standard output: ?+ Equivalent to ?: e -> echo e.msg

  • Print error to error output: ?? Equivalent to ?: e -> eprint e.msg

  • Output error as operation result: ?> Equivalent to ?: e -> e.msg

Error Termination: ?!
#

  • Silently terminate the pipeline when encountering an error Fs.ls -l | ui.pick ?! |_ cp _ /tmp

When the user cancels the selection, subsequent pipeline operations terminate upon encountering an error.

The above methods can apply to any statement or function at the end. Error handling symbols have a higher priority than pipes.

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

Tips

  • Utilizing the characteristics of error handling symbols, you can also provide default values for failed calculations:

    1let e = x -> 0
    2let result = 6 / 0 ?: e
    3echo result              # Outputs default value: 0
    4
    5# Equivalent to
    6let result = 6 / 0 ?: 0
    7echo result              # Outputs default value: 0
  • Use error handling when defining functions

    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.

Error Debugging:
#

  • Error Messages Generally, observing the error message is sufficient to identify the problem. For example:

     1[PARSE FAILED]                        # Syntax parsing error
     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]                                # Runtime 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 Command For further debugging, you can use the debug command.

     1# Simple data debugging:
     2let c = 0..8
     3debug c                     # Output: Range〈0..9,1〉
     4
     5# Complex statement debugging:
     6let a := if a {3 + 5} else { print a is False}
     7debug a
     8
     9# Output:
    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 Module The use of the Log module is also beneficial for error debugging; please refer to the Log Module Documentation.

Related