Bash File Descriptor Trick

Here’s a little bash trick you might not be aware of.

If you wrap a command in <( and ), you get back something that looks like a file name;

$ echo <(ls)

/dev/fd/63

now, that’s not a file, but a file descriptor – a temporary path that unix programs can be tricked into treating like a file.

For example, you can cat the file descriptor just as you would a file:

$ cat <(ls)

Applications
Desktop
Documents
Downloads

So cat thinks it’s reading a file – cat /dev/fd/63 – but it’s actually streaming the output of a command.

So with this trick, any program that takes a file parameter can take a command output. Eg;

  • curl some web content
  • use find or ls to describe files
  • use sed, awk, and grep to modify an existing file

This can be useful when you have a program that takes multiple input files, like diff;

$ diff <(ls src) <(ls src.bak)

3d2
< canto34-syntax.test.ts
5d3
< canto34.test.ts
7d4
< example.test.ts

So here I’ve listed the contents of two directories of source files, and I can see that src has three more files in it than src.bak. Now that’s hard to do otherwise!

Or consider this example – I’ve got two files I know differ only by indentation:

$ diff src/example.ts src.bak/example.ts | wc -l
      82

so, lots of differences. But can I prove they’re the same after trimming?

$ diff <(sed 's|^ *||' src/example.ts)  <(sed 's|^ *||' src.bak/example.ts)

<no output>

Ok then! I’ve used sed to trim leading whitespace from both files, and now the diff is empty – the files are basically the same.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s