Bash脚本中的持久连接

Fer*_*cês 8 bash fifo netcat

我正在尝试使用bash创建持久连接.在终端1上,我保持netcat作为服务器运行:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)
Run Code Online (Sandbox Code Playgroud)

在终端2上,我创建了一个fifo并保留了一只猫:

$ mkfifo fifo
$ cat > fifo
Run Code Online (Sandbox Code Playgroud)

在终端3上,我将fifo作为客户端netcat的输入:

$ cat fifo | nc -v localhost 3000
Connection to localhost 3000 port [tcp/*] succeeded!
Run Code Online (Sandbox Code Playgroud)

在4号航站楼,我发送任何我想要的东西:

$ echo command1 > fifo
$ echo command2 > fifo
$ echo command3 > fifo
Run Code Online (Sandbox Code Playgroud)

回到终端1,我看到收到的命令:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 41722)
command1
command2
command3
Run Code Online (Sandbox Code Playgroud)

一切顺利.但是当我把它放在脚本中时(我称之为fifo.sh),bash无法写入fifo:

在终端1上,同一个监听服务器:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)
Run Code Online (Sandbox Code Playgroud)

在终端2上,我运行脚本:

#!/bin/bash

rm -f fifo
mkfifo fifo
cat > fifo &
pid1=$!
cat fifo | nc -v localhost 3000 &
pid2=$!

echo sending...
echo comando1 > fifo
echo comando2 > fifo
echo comando3 > fifo

kill -9 $pid1 $pid2
Run Code Online (Sandbox Code Playgroud)

终端2的输出是:

$ ./fifo.sh 
Connection to localhost 3000 port [tcp/*] succeeded!
sending...
Run Code Online (Sandbox Code Playgroud)

在终端1上,我只看到连接.没有命令:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 42191)
Connection closed, listening again.
Run Code Online (Sandbox Code Playgroud)

知道为什么它只能以交互方式工作吗?或者有没有其他方法只使用Bash创建持久连接?我不想去Expect,因为我有一个更大的Bash脚本,它在发送command1之后做了一些工作,而command2依赖于command1输出等.

谢谢!

zac*_*kse 3

当进程在脚本中的后台启动时,标准输入将从/dev/null. 这意味着第一个cat命令将在执行后立即读取并发出EOF,这将导致 netcat 在启动后立即退出,因此脚本中稍后的输出将永远不会到达 fifo,因为那里没有活动的侦听器时间。

在这种情况下,当cat > fifo进行求值时,shell 会分叉一个子进程,重定向来自 的标准输入/dev/null,并尝试打开fifo以进行写入。open此时孩子仍处于阻塞呼叫中。请注意,cat直到调用完成后才会执行open

接下来,cat fifo | nc -v localhost 3000就是催生了。cat打开fifo以供读取,这允许第一个子级的阻塞open完成并cat执行第一个子级。

第一个cat继承了其父级的文件描述符,因此它的标准输入被附加到/dev/null,因此它立即读取并发出一个EOF。第二个cat读取EOF并将其传递到 的标准输入nc,这会导致 netcat 退出。

当语句被评估时,由和echo标识的过程就完成了。由于 上不再有侦听器,因此第一个侦听器将永远阻塞。$pid1$pid2fifoecho


我没有纯 shell 修复,但您可以使用 perl 等外部程序来打开占位符编写器,fifo而不是使用 shell 重定向。另外,请注意,在语句之后有一个nc开始的竞争echo(在killnetcat 有机会处理输入/发送输出之前发生),所以这里我在表达式之后添加了一个延迟cat | nc。几乎肯定有更好的解决方案,但这是我想出的:

#!/bin/bash

rm -f fifo
mkfifo fifo
perl -e 'open(my $fh, ">", "fifo"); sleep 3600 while 1' &
pid1=$!
cat fifo | nc -v localhost 3000 &
pid2=$!

sleep 2

echo sending...
echo comando1 > fifo
echo comando2 > fifo
echo comando3 > fifo

kill -9 $pid1 $pid2
Run Code Online (Sandbox Code Playgroud)

希望这有帮助,很好的问题!