Pseudo files for temporary data

In Bash, you can use the command1 <( command0 ) redirection syntax, which redirects command0's stdout and passes it to a command1 that takes a filename as a command-line argument. This is called process substitution.

Some programs that take filename command-line arguments actually need a real random-access file, so this technique won't work for those. However, it works fine with wdiff:

user@host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}

In the background, this creates a FIFO, pipes the command inside the <( ) to the FIFO, and passes the FIFO's file descriptor as an argument. To see what's going on, try using it with echo to print the argument without doing anything with it:

user@host:/path$ echo <( echo hello )
/dev/fd/63

Creating a named pipe is more flexible (if you want to write complicated redirection logic using multiple processes), but for many purposes this is enough, and is obviously easier to use.

There's also the >( ) syntax for when you want to use it as output, e.g.

$ someprogram --logfile >( gzip > out.log.gz )

See also the bash man page "process substitution" section and the Bash redirections cheat sheet for related techniques.


Use a named pipe. By way of illustration:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

The -e tells echo to properly interpret the newline escape (\n). This will block, ie, your shell will hang until something reads the data from the pipe.

Open another shell somewhere and in the same directory:

cat fifo

You'll read the echo, which will release the other shell. Although the pipe exists as a file node on disk, the data which passes through it does not; it all takes place in memory. You can background (&) the echo.

The pipe has a 64k buffer (on linux) and, like a socket, will block the writer when full, so you will not lose data as long as you do not prematurely kill the writer.


wdiff is a special case due to it requiring 2 filename arguments, but for all commands that only require 1 argument and which stubbornly refuse to take anything but a filename argument, there are 2 options:

  • The filename '-' (that is, a minus sign) works about 1/2 of the time. It seems to depend upon the command in question and whether the developer of the command traps that case and handles it as expected. e.g.

    $> ls | cat -

  • There is a psuedo file named /dev/stdin that exists in linux and can be used were a filename is absolutely required by a command. This is more likely to work since it is does not require any special filename handling from the command. If a fifo works, or the bash process substitution method works then this should also work and is not shell specific. e.g.

    $> ls | cat /dev/stdin

Tags:

Bash

Pipe

Files