Use Bash Process Substitution to Diff Streams Without Temporary Files
Discover how to use Bash’s process substitution (<(cmd) and >(cmd)) to compare or merge command outputs on the fly, eliminating temporary files. Follow the step‑by‑step guide, version checks, and recovery options for safe, efficient scripting.
14 Feb 2026, 22:02 UTC

Why Compare Streams Directly?
When scripts need to compare the output of two commands—say, two versions of a configuration file generator—creating temporary files can be a waste of disk I/O and a maintenance headache. Bash’s <(command) and >(command) syntax lets you treat a command’s output as a file descriptor, enabling tools like diff or sort to operate without any intermediate storage.
Desired Outcome
Perform a reliable diff between two command outputs, or pipe one command’s output into another, all without leaving residual files on disk.
Prerequisites
- Bash version 3.0 or newer (check with
bash --version). - Understanding of basic Bash syntax and file descriptors.
- Permission to run
diffor other utilities used in the example. - Shebang line
#!/usr/bin/env bashat the top of scripts.
Step‑by‑Step Procedure
- Verify Bash support
# Check Bash version if [[ "$(bash --version | head -n1 | awk '{print $3}')" < "3.0" ]]; then echo "Process substitution requires Bash 3.0+" >&2 exit 1 fi - Use process substitution with
diff# Compare outputs of two commands # Example: list files in two directories diff <(ls /usr/bin) <(ls /usr/local/bin)The
<(ls /usr/bin)construct creates a named pipe (or /dev/fd entry on BSD) thatdiffreads as if it were a file. - Pipe output into another command
# Merge two sorted streams sort <(cat file1.txt) <(cat file2.txt) > merged.txtNo temporary files are created; the sorted result is written directly to
merged.txt. - Check that no temporary files remain
# After the command finishes, inspect /proc/$PID/fd PID=$$ ls -l /proc/$PID/fd | grep -E 'pipe|fd' | wc -l # Output should be 0 if all descriptors are closed
Expected Checks
- Verify that
diffoutput matches manual comparison of the two commands. - Confirm that
/proc/$PID/fdshows no lingering pipes after the script exits. - Run
ulimit -nto ensure the open file descriptor limit is not exceeded when using many substitutions.
Recovery Options
- If the script runs under a non‑Bash shell, add a guard:
if [[ "$BASH_VERSION" != "*" ]]; then echo "This script requires Bash" >&2 exit 1 fi - For older Bash versions (<3.0), fall back to temporary files:
tmp1=$(mktemp) cmd1 > "$tmp1" cmd2 > "$tmp2" diff "$tmp1" "$tmp2" rm "$tmp1" "$tmp2" - When using process substitution in loops, monitor
ulimit -nand close descriptors explicitly if needed.
Limitations and Practical Checks
- Process substitution is a Bash‑specific feature; scripts will fail in
shordshshells. - On some systems, named pipes can be slower than in‑memory buffers; benchmark if performance is critical.
- Large outputs can overwhelm the pipe buffer; consider using
stdbuf -o0orunbufferif you encounter “broken pipe” errors. - Always test in a non‑production environment before deploying scripts that rely on this feature.
Conclusion
Process substitution lets you treat command outputs as files, enabling efficient, clean comparisons and data flows without temporary artifacts. By checking Bash version, guarding against unsupported shells, and monitoring file descriptor usage, you can integrate this feature safely into production scripts.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.