Thuật ngữ cho những gì bạn đang cố gắng thực hiện là ghép kênh .
Điều này có thể được thực hiện khá dễ dàng trong bash, nhưng nó đòi hỏi một số tính năng bash nâng cao hơn.
Tôi đã tạo một kịch bản dựa trên kịch bản mà bạn nghĩ sẽ làm những gì bạn đang cố gắng thực hiện. Tôi sẽ giải thích nó dưới đây.
#!/bin/bash
manager() {
while IFS= read -r line; do
echo "manager[$1:$BASHPID]: $line"
done
}
fds=()
for (( i=0; i<5; i++ )); do
exec {fd}> >(manager $i)
fds+=( $fd )
done
while IFS= read -r line; do
echo "master: $line"
for fd in "${fds[@]}"; do
printf -- '%s\n' "$line" >&$fd
done
done
manager
là một hàm bash chỉ đơn giản là đọc từ STDIN và ghi định danh của nó và dòng vào STDOUT. Chúng tôi sử dụng $BASHPID
thay vì $$
như $$
không được cập nhật cho subshells (đó là những gì chúng tôi sẽ được sử dụng để khởi động manager
.
fds
là một mảng sẽ chứa các bộ mô tả tệp trỏ đến các ống STDIN của các manager
s khác nhau được sinh ra.
Sau đó, chúng tôi lặp qua và tạo 5 quy trình quản lý. Tôi sử dụng for (( ))
cú pháp thay vì cách bạn đang làm nó vì nó sạch hơn. Đây là bash cụ thể, nhưng một số điều trong kịch bản này là bash cụ thể, vì vậy cũng có thể đi tất cả các cách.
Tiếp theo chúng ta đến exec {fd}> >(manager $i)
. Điều này không có nhiều điều cụ thể bash.
Đầu tiên trong số đó là {fd}>
. Thao tác này sẽ lấy bộ mô tả tệp có sẵn tiếp theo trên hoặc sau số 10, mở một ống có mặt viết của ống được gán cho bộ mô tả tệp đó và gán số mô tả tệp cho biến $fd
.
Việc >(manager $i)
khởi chạy manager $i
và về cơ bản thay thế >(manager $i)
bằng một đường dẫn đến STDIN của quá trình đó. Vì vậy, nếu manager
được khởi chạy là PID 1234, >(manager $i)
có thể được thay thế bằng /proc/1234/fd/0
(đây là phụ thuộc vào hệ điều hành).
Vì vậy, giả sử số mô tả tệp có sẵn tiếp theo là 10 và trình quản lý được khởi chạy với PID 1234, exec {fd}> >(manager $i)
về cơ bản lệnh sẽ trở thành exec 10>/proc/1234/fd/0
và bash hiện có mô tả tệp trỏ đến STDIN của trình quản lý đó.
Sau đó, vì bash đặt số mô tả tệp đó vào $fd
, chúng tôi thêm mô tả đó vào mảng fds
để sử dụng sau.
Phần còn lại của nó là khá đơn giản. $fds
Bậc thầy đọc một dòng từ STDIN, lặp đi lặp lại trên tất cả các mô tả tệp trong và gửi dòng đến tệp đó desciptor ( printf ... >&$fd
).
Kết quả trông như thế này:
$ /tmp/test.sh
hello
master: hello
manager[0:8876]: hello
manager[1:8877]: hello
manager[4:8880]: hello
manager[2:8878]: hello
manager[3:8879]: hello
world
master: world
manager[0:8876]: world
manager[1:8877]: world
manager[3:8879]: world
manager[2:8878]: world
manager[4:8880]: world
Nơi tôi gõ hello
và world
.