linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Processes & resources/process-substitution

kb/processes ── Processes & resources ── intermediate

Process substitution: <(cmd) and >(cmd)

Bash syntax `<(cmd)` substitutes a command as a read-only pseudo-file. `>(cmd)` does it for writing. You get a temporary file you never have to clean up.

view as markdownaka: proc-sub, process-redirection, anonymous-fifo

Why

A command often wants a file as input, but what you have is a command that produces the data. The classic example: diff compares two files, and you want to compare the output of two commands.

Without process substitution, you write to temporary files:

bash
ls /etc | sort > /tmp/a.txt
ls /usr | sort > /tmp/b.txt
diff /tmp/a.txt /tmp/b.txt
rm /tmp/a.txt /tmp/b.txt    # don't forget to clean up

With process substitution, one line:

bash
diff <(ls /etc | sort) <(ls /usr | sort)

How it works

Under the hood, <(cmd) is a /dev/fd/N (where N is some FD, usually 63 and up). Bash:

  1. Runs cmd in a subprocess
  2. Creates a pipe
  3. Substitutes the path /dev/fd/63 into the command line, which reads from that pipe

The command (diff) opens this "file" as an ordinary path and reads the subprocess output. No temporary files are written to disk.

bash
echo <(ls)

▸/dev/fd/63

cat <(echo hello)

▸hello

The mirror form: >(cmd)

>(cmd) is the opposite: a pseudo-file for writing that a command reads its stream from:

bash
echo "data" | tee >(wc -c > /tmp/byte-count.txt) >/dev/null

▸tee writes a copy into the wc -c subprocess

▸wc -c counts the bytes and saves them to a file

Use it to fan the output of one command out to several handlers in parallel:

bash
some_command | tee >(grep ERROR > errors.log) >(grep WARN > warns.log) > /dev/null

Where it does NOT work

  • POSIX /bin/sh: no process substitution. Only bash and zsh have it.
  • A pipe into process substitution: the exit code is lost. The command inside <(...) can fail and the script won't notice, even with set -e. If the exit code matters, write to a file and check it explicitly.
  • Over ssh: ssh host '<(cmd)' won't work, because it runs on the remote side, which may not be bash.

Idioms you will run into

bash
# Compare two directories by content
diff <(ls -la /etc) <(ls -la /etc.bak)
# Check that a command's output matches a file
diff <(my_program) expected.txt && echo OK
# Send STDOUT and STDERR to DIFFERENT files (without 2>&1)
cmd > >(tee out.log) 2> >(tee err.log >&2)
# Use while read to count matches (NOT through a pipe, or the
# variable is lost in a subshell)
count=0
while read -r line; do
    ((count++))
done < <(grep ERROR app.log)
echo "$count"     # ← the variable survived, because there is NO pipe

That last case is a common trap: grep ... | while read; do ((count++)); done does not work (count stays 0), because the pipe runs while in a subshell. Process substitution fixes this.

§ команды

bash
diff <(cmd1) <(cmd2)

Compare the output of two commands without temporary files

bash
while read x; do ...; done < <(cmd)

Loop over a command's lines without losing variables in a subshell

bash
tee >(grep err > errors) >(grep warn > warns) > /dev/null

Parallel fan-out of one stream to several handlers

bash
comm -12 <(sort a) <(sort b)

Find the lines common to two commands (intersection)

§ см. также

  • file-descriptorsFile descriptors (stdin, stdout, stderr)A file descriptor is an integer a process uses to reach an open file, socket, or pipe. Every process gets 0/1/2 = stdin/stdout/stderr.
  • heredocHere-doc and here-string: data inside the scriptHere-doc (`<<EOF ... EOF`) feeds multi-line text to a command's stdin with no temp file. Here-string (`<<<`) does the same for a single line.
  • process-and-pidProcess and PIDA process is a running program with its own PID, memory, open descriptors, and UID. Every process forms a tree rooted at init (PID 1).

§ упоминается в уроках

  • ›intermediate-11-advanced-redirects
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies