Pseudo files for temporary data

78,681

Solution 1

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.

Solution 2

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.

Solution 3

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

Share:
78,681

Related videos on Youtube

Daniel Ezra
Author by

Daniel Ezra

Updated on September 18, 2022

Comments

  • Daniel Ezra
    Daniel Ezra almost 2 years

    I often want to feed relatively short string data (could be several lines though) to commandline programs which accept only input from files (e.g. wdiff) in a repeated fashion. Sure I can create one or more temporary files, save the string there and run the command with the file name as parameter. But it looks to me as if this procedure would be highly inefficient if data is actually written to the disk and also it could harm the disk more than necessary if I repeat this procedure many times, e.g. if I want to feed single lines of long text files to wdiff. Is there a recommended way to circumvent this, say by using pseudo files such as pipes to store the data temporarily without actually writing it to the disk (or writing it only if it exceeds a critical length). Note that wdiff takes two arguments and, as far as I understand it will not be possible to feed the data doing something like wdiff <"text".

    • Admin
      Admin over 11 years
      Can this be solved via xargs?
    • Admin
      Admin over 11 years
      Don't know, but it would not be obvious to me how. As far as I understand xargs would make the input lines from the file string arguments for the command. But I need the opposite.
    • Admin
      Admin over 11 years
      What's wrong with echo $data_are_here | dumb_program?
    • Admin
      Admin over 11 years
      This would support only one input file and not all programs would read from stdin.
    • Admin
      Admin over 11 years
      Hmmm...none of the answers to the question which this is apparently a "duplicate" of include the only answer here (named pipe), which apparently the OP decided to go with...so in that sense this question DID NOT already have an answer.
    • Admin
      Admin over 11 years
      I fail to see how that other answer is a duplicate. None of the answers in that other question apply here. The obvious answer here is to use process substitution (or fifos for shells that lack the process substitution feature)
    • Admin
      Admin over 11 years
      Yes. It's not a duplicate!
    • Admin
      Admin over 2 years
      @StéphaneChazelas, "that other answer is a duplicate" - which one? for posteriority it IMO would be good to re-add link to what you were talking about.
  • Daniel Ezra
    Daniel Ezra over 11 years
    Ok, thanks, this works also with two named pipes and wdiff. But I thought to understand that there is a certain (small) amount of memory available for the pipe as buffer. What happens if I exceed the buffer size?
  • goldilocks
    goldilocks over 11 years
    I added a final paragraph about that issue.
  • Admin
    Admin over 11 years
    /tmp is configure in most distros to use a tmpfs filesystem which is in RAM. When you write a file in /tmp it goes directly to your RAM which makes is a good answer for semi-resilient files that have to be accessed quickly and rewritten many times.
  • chanchal1987
    chanchal1987 almost 10 years
    This is not supported in KSH
  • eel ghEEz
    eel ghEEz about 8 years
    less and openssl like /dev/stdin rather than /dev/fd/NUM :-)
  • Neil McGuigan
    Neil McGuigan almost 8 years
    ksh invented this. You're using a variant of ksh that that doesn't support it
  • Sukima
    Sukima over 6 years
    Some programs that take filename command-line arguments actually need a real random-access file, so this technique won't work for those. What do you do in these cases. For example ssh -F <(vagrant ssh-config) default would be really nice but alas.