Ống bán không đồng bộ


11

Giả sử tôi có đường ống sau:

a | b | c | d

Làm thế nào tôi có thể chờ đợi để hoàn thành c(hoặc b) trong shhoặc bash? Điều này có nghĩa là tập lệnh dcó thể bắt đầu bất cứ lúc nào (và không cần phải chờ) nhưng yêu cầu đầu ra hoàn chỉnh cđể hoạt động chính xác.

Các trường hợp sử dụng là một difftoolcho gitrằng so sánh hình ảnh. Nó được gọi bởi gitvà cần xử lý đầu vào của nó ( a | b | cphần) và hiển thị kết quả so sánh ( dphần). Người gọi sẽ xóa đầu vào được yêu cầu cho ab. Điều này có nghĩa là trước khi trở về từ tập lệnh, quá trình c(hoặc b) phải chấm dứt. Mặt khác, tôi không thể chờ đợi dvì điều này có nghĩa là tôi đang chờ người dùng nhập liệu.

Tôi biết rằng tôi có thể viết kết quả của cmột tệp tạm thời, hoặc có thể sử dụng một FIFO trong bash. (Tuy nhiên, không chắc chắn nếu FIFO sẽ giúp đỡ.) Có thể đạt được điều này mà không cần các tệp tạm thời shkhông?

BIÊN TẬP

Có lẽ nó là đủ nếu tôi có thể tìm ra ID quy trình của quy trình c(hoặc b) một cách đáng tin cậy. Sau đó, toàn bộ đường ống có thể được bắt đầu không đồng bộ và tôi có thể đợi ID tiến trình. Một cái gì đó dọc theo dòng

wait $(a | b | { c & [print PID of c] ; } | d)

CHỈNH SỬA ^ 2

Tôi đã tìm thấy một giải pháp, ý kiến ​​(hoặc vẫn là giải pháp tốt hơn) được chào đón.


Bạn có nghĩa là bạn muốn dbắt đầu xử lý cđầu ra chỉ sau khi cđã hoàn thành? Bạn không muốn dbắt đầu xử lý từng dòng đầu ra?
terdon

@terdon: Không, dcó thể bắt đầu bất cứ khi nào nó thích, nhưng ccần hoàn thành trước khi tôi có thể tiếp tục.
krlmlr

Điều đó dường như là tự mâu thuẫn, nếu dcó thể bắt đầu khi nó thích, chính xác thì bạn đang chờ đợi điều gì?
terdon

@terdon: Mở rộng để hiển thị trường hợp sử dụng.
krlmlr

Nếu dkhông sử dụng đầu ra của cthì có vẻ như không có ý nghĩa gì để tạo dthành một phần của đường ống. Nhưng nếu dkhông sử dụng đầu vào thì dphải hoạt động một lúc trên đầu vào của nó sau khi đã đọc tất cả đầu vào để tiếp cận của bạn để tạo ra bất kỳ sự khác biệt.
Hauke ​​Laging

Câu trả lời:


6
a | b | { c; [notify];} | d

Thông báo có thể được thực hiện, ví dụ bằng tín hiệu đến một PID đã được truyền trong biến môi trường ( kill -USR1 $EXTPID) hoặc bằng cách tạo tệp ( touch /path/to/file).

Một ý tưởng khác:

Bạn thực hiện quy trình tiếp theo (quy trình có thể bắt đầu mà bạn đang chờ) từ đường ống:

a | b | { c; exec >&-; nextprocess;} | d

hoặc là

a | b | { c; exec >&-; nextprocess &} | d

Cảm ơn. Nhưng sau đó, việc tạo một tệp tạm thời cho đầu ra trung gian dài hơn và dễ phân tích hơn (đối với con người). Ngoài ra, làm thế nào để tôi tránh điều kiện cuộc đua với tín hiệu? ... Tôi đã hy vọng cho một giải pháp sạch hơn, nhưng nếu đây là cách để đi, thì nó cũng vậy.
krlmlr

@krlmlr Điều kiện cuộc đua nào?
Hauke ​​Laging

notifycó thể được thực thi trước khi tôi thiết lập bẫy tín hiệu. Làm thế nào tôi có thể đảm bảo không bỏ lỡ tín hiệu đó?
krlmlr

@krlmlr Bạn dừng tập lệnh gọi đường ống cho đến khi nhận được tín hiệu được gửi sau khi trapđã được xác định.
Hauke ​​Laging

Chỉnh sửa của bạn: Đường ống được gọi trong một vòng lặp, qua đó tôi không có quyền kiểm soát. Thật không may, { c; bg; }hoặc { c; exit 0; }dường như không hoạt động.
krlmlr

5

Nếu tôi hiểu chính xác câu hỏi của bạn, điều này sẽ hoạt động:

a | b | c | { (exec <&3 3<&-; d) &} 3<&0

(thủ thuật fd 3 là do một số (hầu hết) shell chuyển hướng stdin sang / dev / null với &).



3

Đây là những gì tôi đã tìm thấy bằng cách dùng thử và lỗi, với sự trợ giúp của đầu vào của Hauke:

a | b | { c; kill -PIPE $$; } | d

Tương đương:

a | b | ( c; kill -PIPE $$; ) | d

(Cái sau rõ ràng hơn, vì {}dù sao cũng sẽ chạy trong một lớp con nếu bên trong một đường ống.)

Một số tín hiệu khác (bao gồm QUIT, TERMUSR1) cũng hoạt động, tuy nhiên trong trường hợp này, mô tả của tín hiệu được hiển thị trên thiết bị đầu cuối.

Tôi tự hỏi nếu đây là ý định ban đầu của PIPEtín hiệu. Theo hướng dẫn :

SIGPIPE: PIPETín hiệu được gửi đến một quy trình khi nó cố ghi vào đường ống mà không có quá trình kết nối với đầu kia.

Điều này có nghĩa là khi tôi gửi tín hiệu đường ống một cách giả tạo đến mạng con, nó sẽ âm thầm chấm dứt, để lại người tiêu dùng cuối cùng ( d).

Điều này hoạt động trong cả shbash.


0

Bạn có thể sử dụng spongechương trình từ gói "moreutils":

a | b | c | sponge | d

miếng bọt biển sẽ cho phần cuối của cđầu ra trước khi đặt nó vào d. Hy vọng đó là những gì bạn muốn.


0

Bạn chỉ có thể làm:

a | b | c | (d ; cat > /dev/null)

Vì vậy, khi dkết thúc, catphần còn lại sẽ hấp thụ phần còn lại của cđầu ra cho đến khi hoàn thành.

Đồng ý. Sau khi bình luận, tôi nghĩ câu trả lời là trực tiếp bắt đầu dtrong nền.

Làm:

a | b | c | (d &)

hoặc sử dụng giải pháp của Stephane Chazelas nếu có vấn đề với dviệc đọc từ stdin .


Tôi e rằng trường hợp sử dụng của tôi khá là ngược lại: ckết thúc sớm hơn dvà tôi phải đợi cho đến khi ckết thúc nhưng không quan tâm d.
krlmlr

Xin lỗi, tôi không hiểu. Bạn muốn làm gì khi ckết thúc và dvẫn đang chạy? Giết d?
angus

dcó GUI và có thể chạy cho đến khi người dùng đóng nó.
krlmlr

OK ... nhưng điều này đã xảy ra. Khi a, bchoàn thành công việc của họ, họ đóng thiết bị xuất chuẩn và thoát ra; và chỉ dcòn lại chạy. Bạn có muốn gửi dđến nền khi ckết thúc? Là nó?
angus

Có, dnên được gửi đến nền sau khi ckết thúc.
krlmlr
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.