Persistent connection in bash script

I am trying to create a persistent connection using bash. On terminal 1, I keep netcat as the server:

$ nc -vlkp 3000 Listening on [0.0.0.0] (family 0, port 3000) 

On terminal 2, I create fifo and save cat:

 $ mkfifo fifo $ cat > fifo 

On terminal 3, I make fifo as a client netcat login:

 $ cat fifo | nc -v localhost 3000 Connection to localhost 3000 port [tcp/*] succeeded! 

On terminal 4, I send everything I want:

 $ echo command1 > fifo $ echo command2 > fifo $ echo command3 > fifo 

Returning to terminal 1, I see the commands received:

 $ 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 

So everything works. But when I put this in a script (I called fifo.sh), bash cannot write to fifo:

On terminal 1, the same listening server:

 $ nc -vlkp 3000 Listening on [0.0.0.0] (family 0, port 3000) 

On terminal 2, I ran a script:

 #!/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 

Output in terminal 2:

 $ ./fifo.sh Connection to localhost 3000 port [tcp/*] succeeded! sending... 

On terminal 1, I see only the connection. No commands:

 $ 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. 

Any idea on why it only works interactively? Or is there another way to create a persistent connection using only Bash? I don't want to look for Expect, because I have a larger bash script that does some work after sending command1, and command2 depends on the output of command1, etc.

Thanks!

+7
bash fifo netcat
source share
1 answer

When a process runs in the background in a script, standard input is redirected from /dev/null . This means that the first cat will read and emit EOF as soon as it is executed, which will cause netcat to exit immediately after launch, so exiting the script later will never get into fifo because it is not an active listener at this time.

In this case, when cat > fifo is evaluated, the shell creates a child process, redirects standard input from /dev/null and tries to open fifo for writing. Currently, the child remains blocked by the open call. Note that cat not executed until the open call completes.

Then cat fifo | nc -v localhost 3000 appears cat fifo | nc -v localhost 3000 cat fifo | nc -v localhost 3000 . cat opens fifo for reading, which allows you to block open from the first child and execute the first cat .

The first cat inherits the descriptors of the parent file, so its standard input is bound to /dev/null , and therefore it reads and emits EOF immediately. The second cat reads the EOF and passes it to standard nc input, which causes netcat to exit.

By the time the echo statements are approved, the processes identified by $pid1 and $pid2 have been completed. Since there are no more listeners on fifo , the first echo will be blocked forever.


I don't have a clean shell fix, but you can use an external program like perl to open the bookmarker up to fifo instead of using shell redirection. Also, note that there is a race with nc , starting with echo statements (where kill happens before netcat has the ability to handle input / send output), so here I added a delay after cat | nc cat | nc expression. There is almost certainly a better solution, but here is what I came up with:

 #!/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 

Hope this helps, big question!

+2
source share

All Articles