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 togoogle.com:80
. If a web browser makes a request tonc
, 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
How to Install Xclip on an Ec2 Instance
Put Command Output into String
Install Sqlite3 Dev and Other Packages in Centos
How to Create Ansible Playbook to Obtain Os Versions of The Remote Hosts
In Shell, Split a Portion of a String with Dot as Delimiter
How to Check If The Sed Command Replaced Some String
How to Avoid Having Version Numbers in .So File Name
What Does '#Pragma Gcc Optimize ("O3")' Mean
Find Out The Time Since Unix Epoch for a Certain Date Time
Get .Net Core Dll Version on Linux
How to Ping Other Containers in a Docker Network Through Their Hostname
I Would Like to Store All Command-Line Arguments to a Bash Script into a Single Variable
Compilation Gcc 4.6.2 (Cannot Compute Suffix of Object Files)
Install Lisp on My Linux Machine
How to Stop Sed from Buffering