giao tiếp giữa nhiều quá trình


13

Tôi có một tập lệnh bash, chạy hàm manager () như một quy trình riêng cho x lần. Làm thế nào có thể chuyển tiếp tin nhắn đến tất cả các quy trình manager () từ trong tập lệnh?

Tôi đã đọc về các đường dẫn ẩn danh nhưng tôi không biết làm thế nào để chia sẻ các tin nhắn với nó .. Tôi đã thử thực hiện với các đường ống có tên, nhưng có vẻ như tôi sẽ phải tạo một đường ống có tên riêng cho mỗi quy trình?

Cách thanh lịch nhất để làm điều này là gì?

Đây là mã của tôi cho đến nay:

#!/bin/bash

manager () {
    while :
    do
        echo "read what has been passed to \$line"
    done
}

x=1
while [ $x -le 5 ]
do
  manager x &
  x=$(( $x + 1 ))
done


while :
do
while read line
do
  echo "What has been passed through the pipe is ${line}"
  # should pass $line to every manager process

done < $1
done

exit 0

Câu trả lời:


25

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

managerlà 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 $BASHPIDthay 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.

fdslà một mảng sẽ chứa các bộ mô tả tệp trỏ đến các ống STDIN của các managers 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 $ivà 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/0và 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. $fdsBậ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õ helloworld.


@Patrick là hoạt động, nhưng bạn có một lỗi đánh máy, {fd} và nó phải là $ {fd}
c4f4t0r

3
@ c4f4t0r Đó không phải là một lỗi đánh máy
Patrick

@Patrick trên suse 11 "bash type.bash type.bash: dòng 10: exec: {fd}: không tìm thấy" i thay đổi để exec $ {fd} và nó hoạt động như thế
c4f4t0r

2
@ c4f4t0r Phiên bản bash trong open suse 11 khá cổ xưa (3.2). Tính năng này đã được thực hiện trong bash 4.0.
Patrick

Cảm ơn rất nhiều thông tin tốt! Một nitpick: Tôi có thể hiểu tại sao bạn sẽ nói echo -- "$line"hoặc printf "%s\n" "$line"- nhưng tại sao bạn cần sử dụng --khi đối số tiếp theo được mã hóa cứng (và không bắt đầu bằng -)?
Scott

0

teebash:

cat foo | tee >(manager) >(manager) >(manager) >(manager) >(manager) >/dev/null

Nếu số lượng người quản lý nên có thể định cấu hình hoặc nếu bạn muốn đầu ra từ các trình quản lý khác nhau không bị lẫn lộn:

export -f manager
cat foo | parallel --pipe --tee manager ::: {1..10}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.