我们都知道mkfifo和管道。第一个创建了一个命名管道,因此必须选择一个名称,最有可能与mktemp之后记得取消链接。另一个创建了一个匿名管道,没有命名和删除的麻烦,但是管道的末端被绑定到管道中的命令,以某种方式获取文件描述符并在其余部分使用它们并不是很方便的脚本。在编译的程序中,我会这样做ret=pipe(filedes);在 Bash 中有很多exec 5<>file人会期待类似的东西,"exec 5<> -"或者"pipe <5 >6"- 在 Bash 中有类似的东西吗?
hta*_*mas 51
您可以在将命名管道附加到当前进程后立即取消链接,这实际上会导致匿名管道:
# create a temporary named pipe
PIPE=$(mktemp -u)
mkfifo $PIPE
# attach it to file descriptor 3
exec 3<>$PIPE
# unlink the named pipe
rm $PIPE
...
# anything we write to fd 3 can be read back from it
echo 'Hello world!' >&3
head -n1 <&3
...
# close the file descriptor when we are finished (optional)
exec 3>&-
Run Code Online (Sandbox Code Playgroud)
如果你真的想避免命名管道(例如文件系统是只读的),你的“掌握文件描述符”的想法也有效。请注意,由于使用了 procfs,这是 Linux 特定的。
# start a background pipeline with two processes running forever
tail -f /dev/null | tail -f /dev/null &
# save the process ids
PID2=$!
PID1=$(jobs -p %+)
# hijack the pipe's file descriptors using procfs
exec 3>/proc/$PID1/fd/1 4</proc/$PID2/fd/0
# kill the background processes we no longer need
# (using disown suppresses the 'Terminated' message)
disown $PID2
kill $PID1 $PID2
...
# anything we write to fd 3 can be read back from fd 4
echo 'Hello world!' >&3
head -n1 <&4
...
# close the file descriptors when we are finished (optional)
exec 3>&- 4<&-
Run Code Online (Sandbox Code Playgroud)
Gil*_*il' 26
虽然我知道没有一个 shell 可以在不分叉的情况下制作管道,但有些确实比基本的 shell 管道更好。
在 bash、ksh 和 zsh 中,假设您的系统支持/dev/fd(现在大多数都支持),您可以将命令的输入或输出与文件名联系起来:<(command)扩展为指定连接到输出的管道的文件名command,并>(command)扩展到一个文件名,该文件名指定连接到输入的管道command。此功能称为进程替换。它的主要目的是将多个命令传入或传出另一个命令,例如,
diff <(transform <file1) <(transform <file2)
tee >(transform1 >out1) >(transform2 >out2)
Run Code Online (Sandbox Code Playgroud)
这对于克服基本壳管的一些缺点也很有用。例如,command2 < <(command1)等价于command1 | command2,只是它的状态是command2。另一个用例是exec > >(postprocessing),它等同于,但比将整个脚本的其余部分放在{ ... } | postprocessing.
Den*_*son 11
Bash 4 有协进程。
协同进程在子外壳中异步执行,就好像命令已用“&”控制运算符终止,并在执行外壳和协同进程之间建立了双向管道。
协进程的格式是:
coproc [NAME] command [redirections]
Run Code Online (Sandbox Code Playgroud)
虽然 @DavidAnderson 的答案<(:)涵盖了所有基础并提供了一些很好的保护措施,但它揭示的最重要的事情是,只要您继续使用 Linux,获得匿名管道就像 一样简单。
因此,对你的问题最简短的回答是:
exec 5<> <(:)
Run Code Online (Sandbox Code Playgroud)
在 macOS 上它不起作用,然后您需要创建一个临时目录来存放命名的 fifo,直到您重定向到它为止。我不知道其他 BSD 的情况。