Nushell
Get Nu!
Getting Started
  • The Nushell Book
  • Command Reference
  • Cookbook
  • Language Reference Guide
  • Contributing Guide
Blog
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
GitHub
Get Nu!
Getting Started
  • The Nushell Book
  • Command Reference
  • Cookbook
  • Language Reference Guide
  • Contributing Guide
Blog
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
GitHub
  • Language Reference Guide
    • Readme
    • Types in the Nu Language
      • Basic Types
        • Any
        • Boolean
        • Integer
        • Float
        • Filesize
        • Duration
        • Datetime
        • Range
        • String
        • Record
        • List
        • Table
        • Closure
        • Nothing
        • Binary
        • Glob
        • Cell-Path
      • Other Data Types

        • Types that cannot be used to declare variables
          • Path
        • Types which are not declarable
          • Error
          • CustomValue
          • Block
      • Type signatures
      • Commands that interact with types
    • Operators
    • Flow control
      • if/else
      • loop
      • while
      • match
      • try/catch
      • break
      • return
      • continue
    • Filters
      • each and par-each
      • Filters to select subsets of data
      • where and filter
      • Understanding the difference between get and select
    • Custom Commands
    • Declarations
    • Variable Scope
    • Strings and Text Formatting
    • Helpers and debugging commands
    • Pipelines
    • MIME Types for Nushell

Pipelines

The pipeline special variable $in

Best practices for pipeline commands

Interaction with Unix pipes

Handling stdout and stderr

You can handle stderr in multiple ways:

  1. Do nothing, stderr will be printed directly
  2. Pipe stderr to the next command, using e>| or e+o>|
  3. Redirect stderr to a file, using e> file_path, or e+o> file_path
  4. Use do -i { cmd } | complete to capture both stdout and stderr as structured data

For the next examples, let's assume this file:

# demo.nu
print "foo"
print -e "barbar"

It prints foo to stdout and barbar to stderr. The following table illustrates the differences between the different redirection styles:

Redirection to a pipeline:

typecommand$result contentsprinted to terminal
|let result = nu demo.nu | str upcase"FOO""barbar"
e>|let result = nu demo.nu e>| str upcase"BARBAR""foo"
o+e>|let result = nu demo.nu e+o>| str upcase"FOO\nBARBAR"nothing

Redirection to a file:

typecommandfile.txt contentsprinted to terminal
o> file_pathnu demo.nu o> file.txt"foo\n""barbar"
e> file_pathnu demo.nu e> file.txt"barbar\n""foo"
o+e> file_pathnu demo.nu o+e> file.txt"foo\nbarbar\n"nothing

complete command:

typecommand$result contents
use completelet result = do { nu demo.nu } | completerecord containing both stdout and stderr

Note that e>| and o+e>| only work with external command, if you pipe internal commands' output through e>| and o+e>|, you will get an error:

ls e>| str length
# => Error:   × `e>|` only works with external streams
# =>    ╭─[entry #1:1:1]
# =>  1 │ ls e>| str length
# =>    ·    ─┬─
# =>    ·     ╰── `e>|` only works on external streams
# =>    ╰────

ls e+o>| str length
# => Error:   × `o+e>|` only works with external streams
# =>    ╭─[entry #2:1:1]
# =>  1 │ ls e+o>| str length
# =>    ·    ──┬──
# =>    ·      ╰── `o+e>|` only works on external streams
# =>    ╰────

You can also redirect stdout to a file, and pipe stderr to next command:

nu demo.nu o> file.txt e>| str upcase
nu demo.nu e> file.txt | str upcase

But you can't use redirection along with o+e>|, because it's ambiguous:

nu demo.nu o> file.txt o+e>| str upcase

Also note that complete is special, it doesn't work with e>|, o+e>|.

Stdio and redirection behavior examples

Pipeline and redirection behavior can be hard to follow when they are used with subexpressions, or custom commands. Here are some examples that show intended stdio behavior.

Examples for subexpression

  • (^cmd1 | ^cmd2; ^cmd3 | ^cmd4)
CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4TerminalTerminal
  • (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) | ^cmd5

It runs (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) first, then pipes stdout to ^cmd5, where both stdout and stderr are directed to the Terminal.

CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4PipedTerminal
  • (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) e>| ^cmd5

It runs (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) first, then pipes stderr to ^cmd5, where both stdout and stderr are directed to the Terminal.

CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4TerminalPiped
  • (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) o+e>| ^cmd5

It runs (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) first, then pipes stdout and stderr to ^cmd5, where both stdout and stderr are directed to the Terminal.

CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4PipedPiped
  • (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) o> test.out
CommandStdoutStderr
cmd1PipedTerminal
cmd2FileTerminal
cmd3PipedTerminal
cmd4FileTerminal
  • (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) e> test.out
CommandStdoutStderr
cmd1PipedFile
cmd2TerminalFile
cmd3PipedFile
cmd4TerminalFile
  • (^cmd1 | ^cmd2; ^cmd3 | ^cmd4) o+e> test.out
CommandStdoutStderr
cmd1PipedFile
cmd2FileFile
cmd3PipedFile
cmd4FileFile

Examples for custom command

Given the following custom commands

def custom-cmd [] {
    ^cmd1 | ^cmd2
    ^cmd3 | ^cmd4
}

The custom command stdio behavior is the same as the previous section.

In the examples below the body of custom-cmd is (^cmd1 | ^cmd2; ^cmd3 | ^cmd4).

  • custom-cmd
CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4TerminalTerminal
  • custom-cmd | ^cmd5

It runs custom-cmd first, then pipes stdout to ^cmd5, where both stdout and stderr are directed to the Terminal.

CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4PipedTerminal
  • custom-cmd e>| ^cmd5

It runs custom-cmd first, then pipes stderr to ^cmd5, where both stdout and stderr are directed to the Terminal.

CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4TerminalPiped
  • custom-cmd o+e>| ^cmd5

It runs custom-cmd first, then pipes stdout and stderr to ^cmd5, where both stdout and stderr are directed to the Terminal.

CommandStdoutStderr
cmd1PipedTerminal
cmd2TerminalTerminal
cmd3PipedTerminal
cmd4PipedPiped
  • custom-cmd o> test.out
CommandStdoutStderr
cmd1PipedTerminal
cmd2FileTerminal
cmd3PipedTerminal
cmd4FileTerminal
  • custom-cmd e> test.out
CommandStdoutStderr
cmd1PipedFile
cmd2TerminalFile
cmd3PipedFile
cmd4TerminalFile
  • custom-cmd o+e> test.out
CommandStdoutStderr
cmd1PipedFile
cmd2FileFile
cmd3PipedFile
cmd4FileFile
Edit this page on GitHub
Contributors: NotTheDr01ds, Wind, fdncred, Jan Klass, kkoang, 132ikl
Prev
Helpers and debugging commands
Next
MIME Types for Nushell