Pipeline Tools
Pipeline Tools
Section titled “Pipeline Tools”tee and xargs for pipeline manipulation.
Write pipeline input to one or more files while passing the original typed objects through to the next command.
Syntax
Section titled “Syntax”tee [OPTIONS] [FILE...]| Flag | Description | Example |
|---|---|---|
-a | Append to files instead of overwriting | ls | tee -a log.txt |
Object behavior
Section titled “Object behavior”tee is a pipeline bridge command. It converts each input object to its BashText representation for file output, but passes the original typed objects through the pipeline unchanged.
This means downstream commands receive the same rich objects they would without tee in the pipeline. The file gets plain text; the pipeline gets types.
ls -la | tee listing.txt | grep '.ps1'In this pipeline:
listing.txtreceives the text rendering of everyLsEntrygrepreceivesLsEntry[]objects and matches against theirBashText- The final output is still typed
LsEntryobjects, not strings
$results = ls -la | tee listing.txt | grep '.ps1'$results[0].GetType().Name # PSCustomObject (LsEntry type)$results[0].Name # "PsBash.psm1"$results[0].SizeBytes # 141234Multiple files
Section titled “Multiple files”Pass multiple file paths to write the same content to several files at once:
echo 'build started' | tee build.log /tmp/build-backup.logBoth build.log and /tmp/build-backup.log receive the text. The TextOutput object passes through.
Examples
Section titled “Examples”Save directory listing while continuing the pipeline:
ls -la | tee listing.txt | grep '.ps1'-rw-r--r-- 1 you you 141234 Apr 2 10:30 PsBash.psm1-rw-r--r-- 1 you you 28400 Apr 2 10:28 PsBash.Tests.ps1The file listing.txt contains the full ls -la output. The grep results are still LsEntry objects.
Append to a log file:
echo 'deploy started' | tee -a deploy.logecho 'step 1 complete' | tee -a deploy.logcat deploy.logdeploy startedstep 1 completeEach echo appends a line rather than overwriting.
Capture intermediate pipeline state for debugging:
cat data.csv | grep -v '^#' | tee filtered.csv | wc -l42The file filtered.csv captures what the pipeline looked like after grep -v removed comments. wc still counts the original objects.
Write to file and inspect object properties:
$entries = ls -la /tmp | tee /tmp/snapshot.txt$entries[0].Permissions # "-rw-r--r--"$entries[0].SizeBytes # 4096Error handling
Section titled “Error handling”If a target directory does not exist, tee reports an error for that file and continues writing to the remaining files:
echo 'hello' | tee /nonexistent/dir/file.txt output.txt# tee: /nonexistent/dir/file.txt: No such file or directoryoutput.txt is still written. The object still passes through.
Comparison
Section titled “Comparison”ls -la | tee listing.txt | grep '.ps1'Bash tee writes raw text to files and passes the same text through stdout. Everything is unstructured text throughout.
ls -la | tee listing.txt | grep '.ps1'PsBash tee writes BashText to files but passes the original typed objects through. grep receives LsEntry[], not strings. Types survive the entire pipeline.
Get-ChildItem | Tee-Object -FilePath listing.txt | Where-Object { $_.Name -match '\.ps1$' }PowerShell’s Tee-Object passes objects through and writes their ToString() rendering to a file. Similar concept, different syntax.
Build and execute commands from standard input. Each input line becomes an argument to the specified command.
Syntax
Section titled “Syntax”xargs [OPTIONS] COMMAND [INITIAL-ARGS...]| Flag | Description | Example |
|---|---|---|
-I REPLACE | Replace occurrences of REPLACE in the command with each input line. Runs the command once per line. | xargs -I {} echo 'Processing {}' |
-n NUM | Pass at most NUM arguments per command invocation | xargs -n 2 echo |
Three modes
Section titled “Three modes”xargs operates in one of three modes depending on the flags:
All input lines are collected and passed as arguments to a single invocation of the command.
echo -e 'one\ntwo\nthree' | xargs echo 'items:'items: one two threeOne command runs: echo 'items:' one two three.
The command runs once per input line. Each occurrence of the replacement string in the arguments is replaced with the current line.
echo -e 'alice\nbob' | xargs -I {} echo 'Hello, {}!'Hello, alice!Hello, bob!Two commands run: echo 'Hello, alice!' and echo 'Hello, bob!'.
Input lines are split into batches of N, and the command runs once per batch.
echo -e 'a\nb\nc\nd' | xargs -n 2 echo 'pair:'pair: a bpair: c dTwo commands run: echo 'pair:' a b and echo 'pair:' c d.
Input handling
Section titled “Input handling”xargs converts each piped object to its BashText representation, splits on newlines, and discards empty lines. Each non-empty line becomes one argument.
ls | xargs echo 'files:'Each filename from ls becomes an argument to echo.
Examples
Section titled “Examples”Delete matching files:
find . -name '*.tmp' | xargs rm -fAll .tmp files found by find are passed as arguments to a single rm -f invocation.
Process each line individually with a placeholder:
cat urls.txt | xargs -I {} echo 'Downloading {}'Downloading https://example.com/file1.tar.gzDownloading https://example.com/file2.tar.gzEach URL is substituted into the echo command one at a time.
Batch arguments in groups:
echo -e 'a\nb\nc\nd\ne\nf' | xargs -n 3 echo 'batch:'batch: a b cbatch: d e fChain with find to process discovered files:
find src -name '*.ps1' | xargs grep 'function'Searches all .ps1 files under src/ for lines containing function.
Build commands from a file list:
cat manifest.txt | xargs -I {} cp {} /backup/Copies each file listed in manifest.txt to the backup directory, one at a time.
Error handling
Section titled “Error handling”Calling xargs with no command produces an error:
echo 'hello' | xargs# xargs: no command specifiedComparison
Section titled “Comparison”find . -name '*.tmp' | xargs rm -fBash xargs supports many additional flags (-0 for null-delimited input, -P for parallel execution, -t for tracing). It reads raw text from stdin.
find . -name '*.tmp' | xargs rm -fPsBash xargs supports -I and -n. It extracts BashText from typed pipeline objects and splits on newlines. Commands are invoked via PowerShell’s & operator.
Get-ChildItem -Filter '*.tmp' -Recurse | ForEach-Object { Remove-Item $_.FullName -Force }PowerShell uses ForEach-Object for per-item processing. There is no built-in xargs equivalent; the pipeline itself serves a similar role with cmdlet-native syntax.