Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

bash - How do I use exec 3>myfifo in a script, and not have echo foo>&3 close the pipe?

Why can't I use exec 3>myfifo in the same manner in a bash script as I can in my terminal?

I'm using named pipes to turn an awk filter into a simple "server", that should be able to take text input from clients, filter it, and flush on NUL.

In terminal 1, the server is running like this:

$ mkfifo to_server from_server;
$ while true; do 
  # Really, this awk script BEGIN's with reading in a huge file, 
  # thus the client-server model
  awk '{sub("wrong", "correct");print;} // {fflush();}' <to_server >from_server; 
  echo "restarting..."; 
done

And I've got a simple script that should put input, ending with a NUL, into the input-pipe, and read from the output pipe, and then exit, without sending an EOF to the server (we don't want the server to restart):

#!/bin/bash
# According to http://mywiki.wooledge.org/BashFAQ/085 , using 
# `exec 3>mypipe; echo foo >&3;` instead of `echo foo >mypipe` 
# should ensure that the pipe does not get the EOF which closes it:
exec 3>to_server;
exec 4<from_server;

cat >&3;
echo -e '' >&3;
while read -rd '' <&4; do echo -n "$REPLY"; break; done;

Now, if I in terminal 2 do $ echo This is wrong | bash client.sh, I get This is correct back, but terminal 1 shows me that the server restarts! If I run the commands from client.sh from within terminal 2, however, it does not restart.

It seems to be related to the exec commands, since I can also do

$ exec 3>to_server; exec 4<from_server;
$ echo "This is wrong" | sh client.sh

and it does not restart. If I then

$ exec 3>&-; exec 4<&-

(which of course restarts it once) and do

$ echo "This is wrong" | sh client.sh

it restarts every time. So it seems the exec commands in the script have no effect. However, putting ls /proc/$$/fd/ after the exec commands in the script shows that they do in fact point to the correct pipes.

What am I missing here?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I think I figured it out!

The exec commands do work, but bash itself closes all open file descriptors on exiting from the script. Adding sleep 5 to the end of the client shows that it takes 5 seconds for the server to finally shut down.

So the solution is just to open some file descriptor to my named pipes from some other terminal, and just keep them open, e.g. in terminal 3:

$ exec 3>to_server; exec 4<from_server
$ # keep open for as long as server is open

or, in the server terminal/script itself:

while true; do 
  # Really, this awk script BEGIN's with reading in a huge file, 
  # thus the client-server model
  awk '{sub("wrong", "correct");print;} // {fflush();}' <to_server >from_server &
  AWKPID=$!
  exec 3>to_server; exec 4<from_server
  wait "$AWKPID"
  echo "restarting..."; 
done

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...