如果我有这个管道:
echo "bar" | nc localhost 6969 < <(echo "foo")
“foo”总是在“bar”之前写入tcp套接字吗?那里有一致的优先顺序吗?
答案1
在
cmd1 | cmd2
cmd1
和与连接到管道写入端(或 ksh93 中的套接字对)的 stdout 和连接到该管道另一端的 stdincmd2
并行启动。cmd1
cmd2
在:
cmd < file
cmd
是从cmd
在 上打开的 stdin开始的file
。
所以你可以看到
cmd1 | cmd2 < file
冲突;您必须选择cmd2
的 stdin 是来自的管道cmd1
还是file
.
在上面的内容中,在大多数 shell 中,<file
重定向完成后 优先后(shell 启动 2 个进程,它们之间有管道,并且然后解释每个命令,包括每个命令内独立的重定向)
这意味着cmd2
标准输入将是file
,并且正在写入的管道echo
将没有读取器(损坏的管道)。因此,在您的情况下,bar
永远不会成功,并且如果在其他进程打开文件之后写入nc
,正在运行的进程echo bar
甚至可能会被终止。bar
zsh
然而,在打开该选项multios
(默认情况下打开)的情况下,zsh
检测到您正在尝试重定向同一文件描述符(此处为 0,stdin)两次,并认为您打算将来自这两个源的数据发送到cmd2
,因此它实际上会启动一个内部的cmd2
管道,而不是将其作为标准cmd1
输入file
喂食器从两个源读取数据并将其(通过另一个管道一个接一个)发送到 的进程cmd2
。
cmd1 < <(cmd2)
只是其中的一种情况cmd1 < file
是file
命名管道(或行为类似于命名管道的东西)cmd2
在另一端进行写入,但在其他方面没有太大不同。
可移植的是,如果您想发送两个命令的输出,或者将一个命令的输出和一个文件的内容发送到某个命令,您可以使用:
{
cmd1
cmd2
} | cmd3
或者:
{
cmd1
cat < file
} | cmd2
所以在这里:
{
echo bar
echo foo
} | nc localhost 6969
答案2
echo
第一个管道数据的重定向nc
被来自进程替换的重定向所覆盖。这意味着nc
只会看到来自进程替换的输入,即字符串foo
。
更一般地说,在
command1 | command2 <data
command2
永远不会读取command1
的输出。
要nc
阅读这两个字符串,请安排它们一起交付,或者使用
{ echo "foo"; echo "bar"; } | nc localhost 6969
或者
nc localhost 6969 < <( echo "foo"; echo "bar" )
答案3
呃,出于某种原因似乎很棘手。也许你可以用 C 编写一些东西,但这可以使用 node.js 解决问题:
#!/usr/bin/env node
'use strict';
const msg = process.argv[2] || process.env.ql_message;
if(!msg){
console.error('quicklock: no message defined in ql_init_message.');
process.exit(1);
}
console.log(msg);
process.stdin.resume().pipe(process.stdout);
在命令行中,您可以像这样使用它:
echo "bar" | initial_message "foo" | nc localhost 6969;
initial_message 只是将一件事记录到 stdout,然后将 stdin 作为传递发送到 stdout。
在这种情况下,我肯定会假设“foo”总是写在“bar”之前。