pipe_path="$(mktemp -u)"
mkfifo "$pipe_path"
exec 3<>"$pipe_path"
rm -f "$pipe_path"
Here, exec associates the file descriptor (3 here, replace with any desired descriptor) with the pipe created by mkfifo. The filesystem path to the pipe is removed immediately after we obtain a file descriptor to it, so that the the only remaining reference to the pipe in the system would be from this script, and thus when the script dies, the kernel will automatically free the pipe.An example use case would be like so: https://unix.stackexchange.com/a/216475/585293
> Open files are represented by decimal numbers starting with zero. The largest possible value is implementation-defined; however, all implementations shall support at least 0 to 9, inclusive, for use by the application.
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...
And from the bash manual:
> Redirections using file descriptors greater than 9 should be used with care, as they may conflict with file descriptors the shell uses internally.
https://www.gnu.org/software/bash/manual/bash.html#Redirecti...
Despite writing shell scripts for nearly three decades, I also was unaware of what POSIX had to say but I can't recall ever needing more than a couple extra FDs at most.
https://www2.dmst.aueb.gr/dds/sw/dgsh/
https://github.com/dspinellis/dgsh
https://news.ycombinator.com/item?id=21700014
dgsh uses Unix domain sockets, not pipes. I don't remember exactly why, but it's in the paper, perhaps to avoid deadlocks compared to pipes.
I'd also be interested in some more examples with pipexec or dgsh!
"Modern Unix systems offer named pipes, also known as fifos, which can be used to hand-craft arbitrary process communication topologies. However, if combined one-to-many and many-to-one piping are setup by using named pipes, another problem will occur. Due to the limited buffering offered by typical programs, deadlocks can easily occur when a process consuming data from many producers with more than one input, blocks waiting for input from one of the processes feeding it. This can cause a second feeding process to block, waiting to send its output to another one of the consumer process’s inputs, and, thereby, blocking the upstream process feeding both processes that provide data to the consumer one."
dspinellis has commented on another dgsh discussion¹(along with you). Interestingly, with a light comparison to pipexec².
I stumbled upon pipexec trying to find a battle tested solution to extend a data munging task where I was relying on zsh's multios³, mostly because orchestrating the interactions with a coproc'd jq for output were fighting me. There is something both frustrating and soothing about finding a seven year old comment pointing out why my path was doomed before I'd even started; people have solved the problem already, plus people far smarter than me also found the trap.
¹ https://news.ycombinator.com/item?id=13352659
² https://news.ycombinator.com/item?id=13358090
³ https://zsh.sourceforge.io/Doc/Release/Redirection.html#Mult...
echo hi > *.txt # writes ALL of the files!
No other shell does that.But I didn't know it was called MULTIOS until now. (I guess that's read "mult I/O's"? I have a hard time not reading it as "multi-OS" :) )
It seems a bit niche to be honest, but it's possible to support in Oils.
---
Oils also uses Unix domain sockets already for the headless shell protocol
https://github.com/oilshell/oil/wiki/Headless-Mode
We could do something like dgsh, but so far I haven't seen a lot of uptake / demand. Every time it's mentioned, somebody kinda wants it, and then it kinda peters out again ... still possible though.
I think flat files work fine for a lot of use cases, and once you add streaming, you also want monitoring, more control over backpressure/queue sizes, etc.
As a noclobber user the footgun is largely hidden to me, but I feel its presence. multios without globbing support would be less useful, but would still work for most of my use cases. Scanning my shell history I see various cases of relying on zsh's ability to apply sorting and filtering to globs with multios' input redirection, but only a couple where I want that in output redirection. The input instances could easily be rewritten using cat and globbing.
Even with multios unset the behaviour is different between zsh and bash. For example, nomultios disables all the expansion, so zsh behaves like more like dash with ': >t{1,2}' creating a file instead producing an error like bash does.
[FWIW, I google'd multiios to link the option in mt original comment. It really feels like it needs double-i, and I read the single i name the same way you do.]
---
I'd be one of those people whose desire for dgsh-like functionality wanes. If it was slight DSL that I could "upgrade" pipelines to I'd probably use it, but not enough to warrant working on it or switching other tooling to support it.
The end of result of this morning's pipeline was breaking my jobs up, and applying some judicious use of nq² to keep track of it. I'd follow your advice and move on to more specialist tools if the job grew significantly or if it became a regular occurrence.
There’s a natural flow of outputs becoming inputs and I’m struggling to identify a situation where I would feed things back into the source. Also, named pipes kind of solve that already.
(I'd love to be wrong though and see a real use case for some cool feedback loop of commands)
Chatbots, where the bot only needs to be line-driven and you can connect it to any CLI chat interface. Or perhaps, run your AI agent attached to a shell, and have it treat standard IO as a shell session.
> websocketd is a small command-line tool that will wrap an existing command-line interface program, and allow it to be accessed via a WebSocket.
Just as there are efforts — both wise and misguided — to represent the building of an SQL query with Python syntax, what Python tools are there to build sh pipelines between processes with a more pythonic syntax? Do they provide value in excess of the novelty tax one has to pay for using a non standard library?
#!/bin/bash
set -beEu -o pipefail
cat <(date) <(false)
echo did not exit non-zero
If this is addressed, it would be worth more time to figure out Pipexec.[1] https://ffmpeg.org/ffmpeg-filters.html#Filtering-Introductio...
> stdin, stdout and stderr are artificial definitions.
Unless you RTFM.
~ $ man stdin | grep stdin,
stdin, stdout, stderr - standard I/O streams
The input stream is referred to as "standard input"; the output stream is referred to as "standard output"; and the error stream
is referred to as "standard error". These terms are abbreviated to form the symbols used to refer to these files, namely stdin, stdout, and stderr.
On program startup, the integer file descriptors associated with the streams stdin, stdout, and stderr are 0, 1, and 2, respectively.
This alignment is, indeed, very much deliberate. Take a peek at this:https://pubs.opengroup.org/onlinepubs/9699919799/functions/s... (also, C11)
They are optional - emphasis mine:
> three streams shall be predefined and need not be opened explicitly
They're artificial in the sense that I don't have to follow laws/rules/customs, I guess. Interesting things may or may not happen if I don't.
In the same way, interesting things happen if I wire stdout to stderr.
The manuals and their tales are not ever-present or absolute, while still true.
Those descriptors do exist. They do useful things. However, there's also no significant consequence to ignoring them.
Abusing them is questionable, of course - but not guaranteed to go poorly