Advertisement
Tritonio

Bidirectional pipes in bash

Jun 2nd, 2022
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.49 KB | None | 0 0
  1. 10
  2.  
  3. bash version 4 has coproc command that allows this done in pure bash without named pipes.
  4.  
  5. From bash man page about coproc command:
  6.  
  7. coproc [NAME] command [redirections]
  8.  
  9. This creates a coprocess named NAME. If NAME is not supplied, the default name is COPROC.
  10.  
  11. The standard output of command is connected via a pipe to a file descriptor in the executing shell, and that file descriptor is assigned to NAME[0]. The standard input of command is connected via a pipe to a file descriptor in the executing shell, and that file descriptor is assigned to NAME[1].
  12.  
  13. Start with a version easy to understand (but does not work). Start entire pipeline under coproc and use extra cat for plumbing.
  14.  
  15. coproc {
  16. cmd1 | cmd2
  17. }
  18. cat <&${COPROC[0]} >&${COPROC[1]}
  19. Buffering is obviously something that needs to be taken care of. Here plain cat will likely break it due to buffering. So use stdbuf to disable buffering by cat:
  20.  
  21. # this is same as above
  22. coproc {
  23. cmd1 | cmd2
  24. }
  25. # replace last line from sample above with:
  26. stdbuf -i0 -o0 cat <&${COPROC[0]} >&${COPROC[1]}
  27. Better still, do away with cat. Break up pipeline into two steps, run 1st section under coproc and 2nd section to connect with 1st.
  28.  
  29. coproc cmd1
  30. cmd2 <&${COPROC[0]} >&${COPROC[1]}
  31. This still assumes that cmd1 and cmd2 handle buffering correctly to make it work.
  32.  
  33. Some other shells also can do coproc as well.
  34.  
  35. That is all the answer above.
  36.  
  37. Below is just some exploration and tests.
  38.  
  39. Here example chains three commands only to make it a little more interesting.
  40.  
  41. # start pipeline
  42. coproc {
  43. cmd1 | cmd2 | cmd3
  44. }
  45.  
  46. # reconnect STDOUT from `cmd3` to STDIN of `cmd1`
  47. stdbuf -i0 -o0 /bin/cat <&${COPROC[0]} >&${COPROC[1]}
  48. Get rid of cat and stdbuf and stay with pure bash. Break it up into two parts, launch the first pipeline under coproc, then launch second part (either a single command or a pipeline), reconnecting it to the first:
  49.  
  50. coproc {
  51. cmd 1 | cmd2
  52. }
  53. cmd3 <&${COPROC[0]} >&${COPROC[1]}
  54. Proof of concept
  55.  
  56. File prog - a worker program participating in looped IO. Just a dummy prog to consume, tag and re-print lines. It is using subshells to avoid buffering problems maybe overkill, it's not the point here.
  57.  
  58. #!/bin/bash
  59.  
  60. # Start this prog with only param "1" to produce some output
  61.  
  62. let c=0
  63. sleep 2
  64.  
  65. [ "$1" == "1" ] && ( echo start )
  66.  
  67. while : ; do
  68. read line
  69. echo "$1:${c} ${line}" 1>&2
  70. sleep 2
  71. ( echo "$1:${c} ${line}" )
  72. let c++
  73. [ $c -eq 3 ] && exit
  74. done
  75. File start_io_loop_with_cat - a demo launcher. This is a version using bash, cat and stdbuf
  76.  
  77. #!/bin/bash
  78.  
  79. # start all 3 commands as one pipeline
  80. coproc {
  81. ./prog 1 \
  82. | ./prog 2 \
  83. | ./prog 3
  84. }
  85.  
  86. # start cat without buffering to connect IO loop
  87. stdbuf -i0 -o0 /bin/cat <&${COPROC[0]} >&${COPROC[1]}
  88. File start_io_loop_pure_bash - another demo launcher. This is a version using pure bash only.
  89.  
  90. #!/bin/bash
  91.  
  92. # start first 2 of 3 commands in the pipeline
  93. coproc {
  94. ./prog 1 \
  95. | ./prog 2
  96. }
  97.  
  98. # start 3rd command connecting IO to 1 and 2 to make the IO loop
  99. ./prog 3 <&${COPROC[0]} >&${COPROC[1]}
  100. Output:
  101.  
  102. > ./start_io_loop_pure_bash
  103. 2:0 start
  104. 3:0 2:0 start
  105. 1:0 3:0 2:0 start
  106. 2:1 1:0 3:0 2:0 start
  107. 3:1 2:1 1:0 3:0 2:0 start
  108. 1:1 3:1 2:1 1:0 3:0 2:0 start
  109. 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start
  110. 3:2 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start
  111. 1:2 3:2 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start
  112. That does it.
  113.  
  114. Share
  115. Improve this answer
  116. Follow
  117. edited Dec 21, 2021 at 15:26
  118. answered Jul 17, 2016 at 16:07
  119. user avatar
  120. AnyDev
  121. 58777 silver badges18
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement