Bash Anonymous Pipes

How to create an anonymous pipe between 2 child processes and know their pids (while not using files/named pipes)?

From the Bash man pages:

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

You are not running a background command, you are running process substitution to read to file descriptor 3.

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

sleep 120 &
child_pid="$!"

wait "${child_pid}"
sleep 120

Edit:
Comment was: I know I can pretty much do this the silly 'while read i; do blah blah; done < <( ./my_proxy_server )'-way, but I don't particularly like the fact that when a script using this approach receives INT or TERM, it simply dies without telling ./my_proxy_server to bugger off too :)

So, it seems like your problem stems from the fact that it is not so easy to get the PID of the proxy server. So, how about using your own named pipe, with the trap command:

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"

You could probably also use kill %1 instead of using $child_pid.

YAE (Yet Another Edit):

You ask how to get the PIDS from:

./my_web_server | ./my_log_parser &

Simples, sort of. To test I used sleep, just like your original.

sleep 400 | sleep 500 &
jobs -l

Gives:

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

So its just a question of extracting those PIDS:

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

I hate calling awk twice here, but anything else is just jumping through hoops.

Example of using named pipes in Linux shell (Bash)

One of the best examples of a practical use of a named pipe...

From http://en.wikipedia.org/wiki/Netcat:

Another useful behavior is using netcat as a proxy. Both ports and hosts can be redirected. Look at this example:

nc -l 12345 | nc www.google.com 80

Port 12345 represents the request.

This starts a nc server on port 12345 and all the connections get redirected to google.com:80. If a web browser makes a request to nc, the request will be sent to google but the response will not be sent to the web browser. That is because pipes are unidirectional. This can be worked around with a named pipe to redirect the input and output.

mkfifo backpipe
nc -l 12345 0<backpipe | nc www.google.com 80 1>backpipe

Redirect output to two unnamed pipe Linux

This should work:

tail -n0 -F /var/log/kern.log | tee "$pipe1" "$pipe2" >/dev/null

The tee output is being redirected to /dev/null and is prevented it to be printed on terminal.

Capture result of bash anonymous FIFO

Although you have not provided any specific examples of cmd1 or cmd2, it would appear that:

cmd1 args >( cmd2 args - )

could be rearranged as:

cmd2 args <(cmd1 args /dev/stdout); echo $?

where the echo statement reports on the status of cmd2.

Specific example

$ cat cmd1
#!/bin/sh
sed "$1" "$2" >"$3"

and:

$ cat cmd2
#!/bin/sh
grep Y "$@"

Let's use a test file:

$ cat file
input

Now, observe that the correct exit codes are reported:

$ cmd2 <( cmd1 's/input/Y/' file /dev/stdout) ; echo $?
Y
0
$ cmd2 <( cmd1 's/input/N/' file /dev/stdout) ; echo $?
1

Further, we can capture stdout into the variable output:

$ output=$( cmd2 <( cmd1 's/input/Y/' file /dev/stdout) ) ; echo code=$? output=$output
code=0 output=Y
$ output=$( cmd2 <( cmd1 's/input/N/' file /dev/stdout) ) ; echo code=$? output=$output
code=1 output=

Writing my own Linux shell with unnamed pipes

After dup you need to close fds[1]. Otherwise the second command process (sort or grep in your example) will not get an EOF from its stdin read. The EOF is needed so that the process knows when to stop processing and exit.

Explicitly, the else block in pipe_command should have a close in it like thus:

} else {
wait(NULL);
dup2(fds[0], 0);
close(fds[1]); /* ADDED THIS LINE */
if(execvp(cmd2[0], cmd2)) {
perror("myShell");
exit(EXIT_FAILURE);
}
}

One more thing to note. Normally the first command process also needs a similar close(fds[0]);. But it is not needed in your case as the second process waits for the first process to exit before calling execvp which results in the first process implicitly closing all its open file descriptors.

How exactly are anonymous pipes implemented in Solaris?

Final answer (in case if anyone finds this and is interested): this buffer created in kernel space is implemented using STREAMS: (source: fifonode.h in illumos gate, thanks to jamieguinan)

     struct msgb    *fn_mp;     /* message waiting to be read */
struct msgb *fn_tail; /* last message to read */

Information about struct msgb (part of STREAMS) can be read in man msgb(9).



Related Topics



Leave a reply



Submit