2

I want to be able to write data to a file descriptor then read it back later in bash.

This would look like:

# some line to create LOOPBACK_FD
echo foo >${LOOPBACK_FD}
cat <${LOOPBACK_FD}
# foo is printed

I know that I can use variables to store the output of commands like in:

MYMESSAGE=$(echo foo)
echo ${MYMESSAGE}

memfd_create does something like what I want but there'd probably be issues with the file offset and it seems bash doesn't even use it.

Maybe there's a special device that can do this?

Edit: I'm looking for a solution which doesn't require making a new node in the filesystem.

8
  • It seems you want to use a temporary file?
    – Kusalananda
    Sep 27 at 19:32
  • Does it have to be a single FD or could you use a pair of read/write FDs?
    – user1686
    Sep 27 at 19:46
  • Are you looking for a named pipe, perhaps? See this question
    – bxm
    Sep 27 at 20:27
  • Sorry, I should have been more specific. I'm looking for something that doesn't need to have its own name in the filesystem. Two fds would work, like the two ends of a pipe. Not sure how to make an unnamed pipe besides | though.
    – jrpear
    Sep 27 at 20:37
  • One way in bash and several other shells would be read MYMESSAGE <(echo foo), but I'm guessing you want the data to persist between commands in your script, and perhaps even persist after one script writes, so a different script can read a few seconds/minutes/hours later.
    – Sotto Voce
    Sep 27 at 20:54

1 Answer 1

3
echo foo >${LOOPBACK_FD}
cat <${LOOPBACK_FD}

That will not work -- no matter how LOOPBACK_FD is created or opened, or if it's accessible via the filesystem or not.

The cat will keep waiting for an EOF which will not come as long as the calling script (which is waiting for cat to terminate) will keep the writing end of the pipe open.

Something that may work with simple examples (but will run into deadlocks and buffering issues with anything non-trivial) is using read instead of cat to get just a line from the pipe, without trying to slurp it whole.

Edit: I'm looking for a solution which doesn't require making a new node in the filesystem.

There are no "anonymous" pipes in Linux; even those created with the pipe(2) system call or with | in the shell are accessible via /proc/{pid}/fd/{fd} or /proc/self/fd/{fd}; they will always "create" a new node in filesystem.

But you can use that feature to open to writing end of an input pipe (or vice versa), which could make for an "clever" answer to your XY problem:

#! /bin/bash
exec {fd}< <(:) {fd}<>/proc/self/fd/$fd

echo eenie >&$fd
read message <&$fd; echo "$message"

echo meenie >&$fd
read message <&$fd; echo "$message"
1
  • Great answer! Stricktly speaking, you could open the pipe in non-block mode like with zmodload zsh/system; sysopen -o nonblock -rwu fd <(:) in zsh instead of bash. Then cat would work though also output some cat: -: Resource temporarily unavailable error message. Sep 28 at 5:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.