Assume that I have programs P0
, P1
, ...P(n-1)
for some n > 0
. How can I easily redirect the output of program Pi
to program P(i+1 mod n)
for all i
(0 <= i < n
)?
For example, let's say I have a program square
, which repeatedly reads a number and than prints the square of that number, and a program calc
, which sometimes prints a number after which it expects to be able to read the square of it. How do I connect these programs such that whenever calc
prints a number, square
squares it returns it to calc
?
Edit: I should probably clarify what I mean with "easily". The named pipe/fifo solution is one that indeed works (and I have used in the past), but it actually requires quite a bit of work to do properly if you compare it with using a bash pipe. (You need to get a not yet existing filename, make a pipe with that name, run the "pipe loop", clean up the named pipe.) Imagine you could no longer write prog1 | prog2
and would always have to use named pipes to connect programs.
I'm looking for something that is almost as easy as writing a "normal" pipe. For instance something like { prog1 | prog2 } >&0
would be great.
A pipe in Bash takes the standard output of one process and passes it as standard input into another process. Bash scripts support positional arguments that can be passed in at the command line. Guiding principle #1: Commands executed in Bash receive their standard input from the process that starts them.
The pipe character | is used to connect the output from one command to the input of another. > is used to redirect standard output to a file. Try it in the shell-lesson-data/exercise-data/proteins directory!
Breaking from a while LoopUse the break statement to exit a while loop when a particular condition realizes. The following script uses a break inside a while loop: #!/bin/bash i=0 while [[ $i -lt 11 ]] do if [[ "$i" == '2' ]] then echo "Number $i!" break fi echo $i ((i++)) done echo "Done!"
After spending quite some time yesterday trying to redirect stdout
to stdin
, I ended up with the following method. It isn't really nice, but I think I prefer it over the named pipe/fifo solution.
read | { P0 | ... | P(n-1); } >/dev/fd/0
The { ... } >/dev/fd/0
is to redirect stdout to stdin for the pipe sequence as a whole (i.e. it redirects the output of P(n-1) to the input of P0). Using >&0
or something similar does not work; this is probably because bash assumes 0
is read-only while it doesn't mind writing to /dev/fd/0
.
The initial read
-pipe is necessary because without it both the input and output file descriptor are the same pts device (at least on my system) and the redirect has no effect. (The pts device doesn't work as a pipe; writing to it puts things on your screen.) By making the input of the { ... }
a normal pipe, the redirect has the desired effect.
To illustrate with my calc
/square
example:
function calc() { # calculate sum of squares of numbers 0,..,10 sum=0 for ((i=0; i<10; i++)); do echo $i # "request" the square of i read ii # read the square of i echo "got $ii" >&2 # debug message let sum=$sum+$ii done echo "sum $sum" >&2 # output result to stderr } function square() { # square numbers read j # receive first "request" while [ "$j" != "" ]; do let jj=$j*$j echo "square($j) = $jj" >&2 # debug message echo $jj # send square read j # receive next "request" done } read | { calc | square; } >/dev/fd/0
Running the above code gives the following output:
square(0) = 0 got 0 square(1) = 1 got 1 square(2) = 4 got 4 square(3) = 9 got 9 square(4) = 16 got 16 square(5) = 25 got 25 square(6) = 36 got 36 square(7) = 49 got 49 square(8) = 64 got 64 square(9) = 81 got 81 sum 285
Of course, this method is quite a bit of a hack. Especially the read
part has an undesired side-effect: termination of the "real" pipe loop does not lead to termination of the whole. I couldn't think of anything better than read
as it seems that you can only determine that the pipe loop has terminated by try to writing write something to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With