A little useful trick for making the input / output of a command act as a temporary file into a larger command.
Syntax
<(command)or
>(command)The shell secretly creates a pipe/FIFO or /dev/fd/* file descriptor behind the scenes, then substitutes that fake filename into the command.
<(...) = “pretend this command output is a file”
>(...) = “pretend this command input is a file”
This is most useful when a command requires two files (or filenames), and doesn’t allow for stdin input.
Example usage
The diff example (Input substitution)
An example is the ‘diff’ command:
diff file1 file2
The diff command requires file inputs:
❯ diff --help
Usage: diff [OPTION]... FILES
...
FILES are 'FILE1 FILE2' or 'DIR1 DIR2' or 'DIR FILE' or 'FILE DIR'.A common example for this use case is if you have two text files, and you need to sort them, and then get the difference. A quick way to do that would be:
diff <(sort a.txt) <(sort b.txt)Bash creates temporary file descriptors such as /dev/fd/88 or /dev/fd/89.
The above example would then be roughly equivalent to:
diff /dev/fd/88 /dev/fd/89`which allows diff to act like it received files.
The tee example (Output substitution)
Example:
echo hello | tee >(wc -c)In this instance, tee duplicates the output, where one copy goes to the terminal, and the other goes to wc -c
So the resulting output would be:
hello
6Useful for logging, checksums, multiple outputs, etc.
The double bracket example
Posts like MLG_Sinon’s example and Geirha’s example both show cases where you can use a < < to read lines of a command’s output.
Take this example:
find . | while read x; do
count=$((count+1))
doneIn Bash, that loop may run in a subshell, so count disappears afterward.
while read x; do
count=$((count+1))
done < <(find .)Now the loop runs in the current shell.
As Geirha explains: “Each part of a pipeline runs in separate subshells, and any variables modified in a subshell are gone after the subshell ends. “
$ printf '%s\n' one two three | mapfile -t lines
$ printf '%d lines\n' "${#lines[@]}"
0 lines
$ mapfile -t lines < <(printf '%s\n' one two three)
$ printf '%d lines\n' "${#lines[@]}"
3 linesOther examples
Compare command outputs
diff <(ls dir1) <(ls dir2)Feed multiple streams into one command
comm <(sort file1) <(sort file2)Logging while preserving output
make > >(tee build.log)Hash data without temp files
md5sum <(curl -s example.com)