Bạn biết đấy, tôi không tin rằng bạn nhất thiết cần một vòng phản hồi lặp đi lặp lại như sơ đồ của bạn, nhiều đến mức bạn có thể sử dụng một đường ống liên tục giữa các bộ xử lý . Sau đó, một lần nữa, có thể không có quá nhiều sự khác biệt - một khi bạn mở một dòng trên bộ đồng xử lý, bạn có thể thực hiện các vòng lặp kiểu điển hình chỉ cần viết thông tin và đọc thông tin từ nó mà không làm bất cứ điều gì khác thường.
Ở nơi đầu tiên, nó sẽ xuất hiện bclà một ứng cử viên chính cho việc đồng xử lý cho bạn. Trong bcbạn có thể các definechức năng có thể làm khá nhiều những gì bạn yêu cầu trong mã giả của bạn. Ví dụ, một số chức năng rất đơn giản để thực hiện việc này có thể trông giống như:
printf '%s()\n' b c a |
3<&0 <&- bc -l <<\IN <&3
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
IN
... sẽ in ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
Nhưng tất nhiên, nó không kéo dài . Ngay sau khi phần phụ chịu trách nhiệm printfthoát khỏi đường ống (ngay sau khi printfghi a()\nvào đường ống) , đường ống bị phá hủy và bcđầu vào của nó đóng lại và nó cũng thoát ra. Điều đó gần như không hữu ích như nó có thể.
@derobert đã đề cập đến các FIFO như có thể có bằng cách tạo một tệp ống có tên với mkfifotiện ích. Đây thực chất chỉ là các đường ống, ngoại trừ nhân hệ thống liên kết một mục hệ thống tập tin với cả hai đầu. Đây là rất hữu ích, nhưng nó sẽ đẹp hơn nếu bạn có thể có một đường ống mà không có nguy cơ nó bị rình mò trong hệ thống tập tin.
Khi nó xảy ra, vỏ của bạn làm điều này rất nhiều. Nếu bạn sử dụng một lớp vỏ thực hiện thay thế quá trình thì bạn có một phương tiện rất đơn giản để có được một đường ống lâu dài - loại mà bạn có thể gán cho một quá trình nền mà bạn có thể giao tiếp.
Trong bashVí dụ, bạn có thể thấy cách thức hoạt động thay thế tiến trình:
bash -cx ': <(:)'
+ : /dev/fd/63
Bạn thấy nó thực sự là một sự thay thế . Shell thay thế một giá trị trong quá trình mở rộng tương ứng với đường dẫn đến một liên kết đến một đường ống . Bạn có thể tận dụng điều đó - bạn không cần bị hạn chế chỉ sử dụng đường ống đó để liên lạc với bất kỳ quy trình nào chạy trong chính sự ()thay thế ...
bash -c '
eval "exec 3<>"<(:) "4<>"<(:)
cat <&4 >&3 &
echo hey cat >&4
read hiback <&3
echo "$hiback" here'
... mà in ...
hey cat here
Bây giờ tôi biết rằng các shell khác nhau thực hiện việc đồng xử lý theo các cách khác nhau - và có một cú pháp cụ thể bashđể thiết lập một (cũng có thể là một cho zshcả) - nhưng tôi không biết những thứ đó hoạt động như thế nào. Tôi chỉ biết rằng bạn có thể sử dụng cú pháp trên để thực hiện hầu như cùng một việc mà không cần tất cả sự nghiêm khắc trong cả hai bashvà zsh- và bạn có thể làm một điều rất giống nhau trong dashvà busybox ashđể đạt được cùng một mục đích với các tài liệu ở đây (bởi vì dashvà busyboxlàm ở đây- tài liệu với các đường ống chứ không phải các tập tin tạm thời như hai người khác làm) .
Vì vậy, khi áp dụng vào bc...
eval "exec 3<>"<(:) "4<>"<(:)
bc -l <<\INIT <&4 >&3 &
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
INIT
export BCOUT=3 BCIN=4 BCPID="$!"
... đó là phần khó khăn. Và đây là phần thú vị ...
set --
until [ "$#" -eq 10 ]
do printf '%s()\n' b c a >&"$BCIN"
set "$@" "$(head -n 3 <&"$BCOUT")"
done; printf %s\\n "$@"
... mà in ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
#...24 more lines...
b=3.92307618030433853649
c=-.70433330413228041035
a=.29566669586771958965
... và nó vẫn đang chạy ...
echo a >&"$BCIN"
read a <&"$BCOUT"
echo "$a"
... mà chỉ được cho tôi những giá trị cuối cùng cho bc's athay vì gọi các a()chức năng để tăng nó và in ...
.29566669586771958965
Trên thực tế, nó sẽ tiếp tục chạy cho đến khi tôi giết nó và phá vỡ các đường ống IPC của nó ...
kill "$BCPID"; exec 3>&- 4>&-
unset BCPID BCIN BCOUT