Shell:两个命令的STDIN/STDOUT的相互管道

nod*_*kai 3 pipe io-redirection shell-script ipc

当我们使用 POSIX shell 运行它时,

$ cmd0 | cmd1
Run Code Online (Sandbox Code Playgroud)

cmd0 的 STDOUT 通过管道传输到 cmd1 的 STDIN。

问:除此之外,我如何将 cmd1 的 STDOUT 通过管道传输到 cmd0 的 STDIN?

必须使用重定向自/进入命名管道 (FIFO) 吗?我不太喜欢命名管道,因为它们占用了一些文件系统路径,我需要担心名称冲突。或者我必须通过 C、Python 或一些通用编程语言调用 pipe(2) 吗?

(cmd0 和 cmd1 都执行一些网络 I/O,因此它们不会永远相互阻塞。)

Sté*_*las 16

在具有双向管道的系统(不是 Linux)上,您可以执行以下操作:

cmd0 <&1 | cmd1 >&0
Run Code Online (Sandbox Code Playgroud)

在 Linux 上,您可以执行以下操作:

: | { cmd1 | cmd2; } > /dev/fd/0
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为在 Linux(和 Cygwin,但通常不是其他系统)上/dev/fd/xx管道(命名或未命名)的 fd 就像命名管道,也就是说,在读取模式下打开它可以让您在读取端和写入模式下让你的写作结束。

使用yashshell及其x>>|y 管道重定向运算符

{ cmd0 | cmd1; } >>|0
Run Code Online (Sandbox Code Playgroud)

随着与coproc支持炮弹

专用工具方法(从这个非常相似问题的答案中无耻地复制):

使用 pipexec

pipexec [ A /path/to/cmd0 ] \
        [ B /path/to/cmd1 ] \
        '{A:1>B:0}' '{A:0>B:1}'
Run Code Online (Sandbox Code Playgroud)

或使用 dpipe

dpipe cmd0 = cmd1
Run Code Online (Sandbox Code Playgroud)

或使用socat

socat EXEC:cmd0 EXEC:cmd1,nofork                 # using socketpairs
socat EXEC:cmd0,commtype=pipes EXEC:cmd1,nofork  # using pipes
Run Code Online (Sandbox Code Playgroud)

我不知道python,但这在 中也相对容易完成perl

perl -e 'pipe STDOUT,STDIN; exec "cmd0 | cmd1"'
Run Code Online (Sandbox Code Playgroud)

您也可以始终求助于命名管道,但是为它们找到唯一的名称和一些安全目录来创建它们,限制对它们的访问(因此其他进程无法打开它们并进行干扰)和之后的清理成为难以解决的额外问题克服可靠和便携。

无论如何,要小心死锁!

  • @Kentzo,再次不,`perl` 不会在这里读取或写入任何内容。当 `cmd0` 和 `cmd1` 启动时,它就消失了(已被 `sh` 取代)。你可以用`perl -e '管道STDOUT,STDIN; exec "ps -f &gt;&amp;2"'` 或 `perl -e 'pipe STDOUT,STDIN; exec q((lsof -p "$$" +E -ad0,1 &gt;&amp;2); exit)'` 说服自己。 (2认同)