How can I create an anonymous pipe between two child processes and find out their pids (not using files / named pipes)?

Please note that these questions have been edited after several comments I received. At first I wanted to break my goal down into smaller parts to keep things simpler (and possibly expand my knowledge on different fronts), but it seems like I went too far with simplicity :). So here I am asking a big question.

Using bash, is there a way to create an anonymous pipe between two child processes and find out their pids?

The reason I am asking is when you are using a classic pipeline like

cmd1 | cmd2 &

      

you lose the ability to send signals to cmd1. In my case, the actual commands I run are

./my_web_server | ./my_log_parser &

      

my_web_server is a basic web server that dumps a lot of logging information to it stdout my_log_parser is a log parser I wrote that reads all the logging information it gets from my_web_server and basically only fetches certain values ​​from the log ( in fact it actually stores the entire log as it is received, but additionally creates an additional csv file with the values ​​it finds).

The problem I'm running into is that my_web_server never actually stops on its own (it's a webserver, you don't want this from a webserver :)). So after I'm done, I need to stop it myself. I would like for a bash script to do this when I stop it (bash script), either via SIGINT or SIGTERM.

For something like this, traps are the way to go. Basically, I would create a trap for INT and TERM, and the function it would call would kill my_web_server, but ... I don't have the pid, and although I know I can find it via ps, I'm looking for a pretty solution: ).

Some of you might say, "Well, why don't you just kill my_log_parser and let my_web_server die on its own with SIGPIPE?" The reason I don't want to kill it is when you kill a process that is at the end of the pipeline, the output buffer of the process before it is not flushed. Ergo, you are losing things.

I've seen several solutions here and elsewhere that suggested storing my_web_server pid in a file. This is the solution that works. You can write a pipeline by playing around with file indices a little. I don't like this solution, however, because I have to generate files. I don't like the idea of ​​creating arbitrary files just to store the 5 character PID :).

What I have now been doing is this:

#!/bin/bash

trap " " HUP

fifo="$( mktemp -u "$( basename "${0}" ).XXXXXX" )"
mkfifo "${fifo}"

<"${fifo}" ./my_log_parser &
parser_pid="$!"

>"${fifo}" ./my_web_server &
server_pid="$!"

rm "${fifo}"

trap '2>/dev/null kill -TERM '"${server_pid}"'' INT TERM

while true; do
  wait "${parser_pid}" && break
done

      

This solves the issue where I cannot terminate my_web_server when the script receives a SIGINT or SIGTERM. This seems to be more readable than any file descriptor hacking to end up using a file to store my_web_server pid, which I think is good because it improves readability.

But it still uses a file (named pipe). Even though I know it uses a file (named pipe) for my_web_server and my_log_parser to talk (which is a pretty good reason), and the file is quickly erased from disk very quickly after it is created, it is still a file :).

Does anyone of you know a way to accomplish this task without using any files (named pipes)?

+3


source to share


1 answer


From the Bash pages man

:

!      Expands  to  the  process ID of the most recently executed back-
       ground (asynchronous) command.

      

You don't have a background command, you are doing process substitution to read file descriptor 3.

The following steps, but I'm not sure if this is what you are trying to achieve:

sleep 120 &
child_pid="$!"

wait "${child_pid}"
sleep 120

      

Edit: The comment was: I know I can pretty much make it silly "by reading i; do blah blah; done <(./my_proxy_server) 'is the way to go, but I don't particularly like the fact that when the script using this approach gets INT or TERM, it just dies without specifying. / my _proxy_server disable too :)

So, it looks like your problem is related to the fact that getting the PID of the proxy server is not that easy. So, how about using your own named pipe with the command trap

:

pipe='/tmp/mypipe'
mkfifo "$pipe"
./my_proxy_server > "$pipe" &

child_pid="$!"
echo "child pid is $child_pid"

# Tell the proxy server to bugger-off
trap 'kill $child_pid' INT TERM

while read
do
    echo $REPLY
    # blah blah blah
done < "$pipe"

rm "$pipe"

      

Maybe you can also use kill %1

instead $child_pid

.



YAE (one more edit):
You are asking how to get PIDS from:

./my_web_server | ./my_log_parser &

      

The Simpsons. For testing I used sleep

like your original.

sleep 400 | sleep 500 &
jobs -l

      

gives:

[1]+  8419 Running                 sleep 400
      8420 Running                 | sleep 500 &

      

So, this is just a question about retrieving these PIDS:

pid1=$(jobs -l|awk 'NR==1{print $2}')
pid2=$(jobs -l|awk 'NR==2{print $1}')

      

I don't like calling awk

twice here, but everything else is just jumping through hoops.

+2


source







All Articles