Hiểu các lệnh đường ống trong Unix / Linux


16

Tôi có hai chương trình đơn giản: AB. Asẽ chạy đầu tiên, sau đó Bnhận được stdoutout của người Adùng và sử dụng nó như là stdin của nó. Giả sử tôi đang sử dụng hệ điều hành GNU / Linux và cách đơn giản nhất có thể để làm điều này sẽ là:

./A | ./B

Nếu tôi phải mô tả lệnh này, tôi sẽ nói rằng đó là lệnh lấy đầu vào (tức là đọc) từ nhà sản xuất ( A) và ghi cho người tiêu dùng ( B). Đó có phải là một mô tả chính xác? Tôi có thiếu thứ gì không?



Đó không phải là lệnh, nó là một đối tượng kenerl được tạo bởi quá trình bash, được sử dụng như thiết bị xuất chuẩn của quy trình A và stdin khi B. Hai quy trình được bắt đầu gần như cùng một lúc.
炸鱼 薯条

1
@ 炸鱼 Bạn đã đúng - đối với đường ống hạt nhân là một đối tượng trong hệ thống tập tin pipefs, nhưng theo như liên quan đến vỏ - về mặt kỹ thuật đó là lệnh đường ống
Sergiy Kolodyazhnyy

Câu trả lời:


26

Điều duy nhất về câu hỏi của bạn nổi bật là sai là bạn nói

A sẽ chạy trước, sau đó B nhận được thiết bị xuất chuẩn của A

Trên thực tế, cả hai chương trình sẽ được bắt đầu cùng một lúc. Nếu không có đầu vào Bkhi nó cố đọc, nó sẽ chặn cho đến khi có đầu vào để đọc. Tương tự như vậy, nếu không có ai đọc đầu ra từ đó A, ghi của nó sẽ chặn cho đến khi đầu ra của nó được đọc (một số sẽ được đệm bởi đường ống).

Điều duy nhất đồng bộ hóa các quy trình tham gia vào một đường ống là I / O, tức là đọc và viết trên đường ống. Nếu không có văn bản hoặc đọc xảy ra, thì hai quá trình sẽ chạy hoàn toàn độc lập với nhau. Nếu một người bỏ qua việc đọc hoặc ghi của người khác, quy trình bị bỏ qua sẽ chặn và cuối cùng bị giết bởi SIGPIPEtín hiệu (nếu đang viết) hoặc nhận được một điều kiện cuối tập tin trên luồng đầu vào tiêu chuẩn của nó (nếu đọc) khi quá trình khác kết thúc .

Cách thành ngữ để mô tả A | Blà một đường ống chứa hai chương trình. Đầu ra được tạo ra trên đầu ra tiêu chuẩn từ chương trình đầu tiên có sẵn để được đọc trên đầu vào tiêu chuẩn bởi đầu vào thứ hai ("[đầu ra của] Ađược dẫn vào [đầu vào của] B"). Vỏ làm hệ thống ống nước cần thiết để cho phép điều này xảy ra.

Nếu bạn muốn sử dụng các từ "người tiêu dùng" và "nhà sản xuất", tôi cho rằng điều đó cũng ổn.

Thực tế là đây là những chương trình viết bằng C không liên quan. Thực tế rằng đây là Linux, macOS, OpenBSD hoặc AIX không liên quan.


2
Ghi vào một tệp tạm thời đã được sử dụng trong DOS, vì nó không hỗ trợ nhiều quy trình.
CSM

2
@AlexVong Lưu ý rằng ví dụ của bạn với một tệp tạm thời không hoàn toàn tương đương. Một chương trình có thể chọn tìm kiếm mặc dù nội dung của tệp, nhưng dữ liệu đi ra khỏi đường ống là không thể tìm kiếm. Một bài kiểm tra tốt hơn sẽ được sử dụng mkfifođể tạo một đường ống có tên, sau đó bắt đầu B trong phần đọc nền từ đường ống, và sau đó A viết cho nó. Đây là cách chọn nit, vì hiệu ứng sẽ giống nhau.
Kusalananda

2
@AlexVong Các đơn giản hóa được thực hiện trong bài viết đó đã ly dị nó với các đường ống thực; việc thực hiện song song thực sự là ngữ nghĩa, không phải là tối ưu hóa. Đó là một lời giải thích hợp lý cho trẻ em về đánh giá hoặc thành phần đơn nguyên cho ai đó đã nhìn thấy các đường ống vỏ, nhưng nó không hợp lệ theo hướng khác. Phiên bản fifo của Kusalananda gần hơn, nhưng các phần lan truyền lỗi của mô hình thực sự quan trọng và không thể sao chép. (tất cả những gì tôi nói với tư cách là một người rất quan tâm đến "đường ống vỏ chỉ là thành phần chức năng")
Michael Homer

6
@AlexVong Không, điều đó hoàn toàn không đúng. Điều đó không thể giải thích ngay cả những điều đơn giản như yes | sed 10q
Chú Billy

1
@UncleBilly Tôi đồng ý với ví dụ của bạn. Điều này cho thấy việc thực hiện song song thực sự cần thiết cũng được Michael lưu ý. Nếu không, chúng tôi sẽ không chấm dứt.
Alex Vong

2

Thuật ngữ thường được sử dụng trong tài liệu là "đường ống", bao gồm một hoặc nhiều lệnh, xem định nghĩa POSIX Vì vậy, về mặt kỹ thuật, đó là hai lệnh bạn có ở đó, hai quy trình con cho trình bao (có thể là fork()+exec()lệnh ngoài hoặc lệnh con)

Đối với phần sản xuất-tiêu dùng , đường ống có thể được mô tả theo mẫu đó, vì:

  • Nhà sản xuất và người tiêu dùng chia sẻ bộ đệm kích thước cố định và ít nhất là trên Linux và MacOS X, có kích thước cố định cho bộ đệm đường ống
  • Nhà sản xuất và người tiêu dùng là lỏng lẻo-coupled, lệnh trong đường ống không biết về sự tồn tại của nhau (trừ khi họ đang tích cực kiểm tra /proc/<pid>/fdthư mục).
  • Các nhà sản xuất viết thư stdoutvà người tiêu dùng đọc stdinnhư thể họ là một lệnh duy nhất được thực thi, hay còn gọi là họ có thể tồn tại mà không cần nhau .

Sự khác biệt tôi thấy ở đây là không giống như Nhà sản xuất-Người tiêu dùng trong các ngôn ngữ khác, các lệnh shell sử dụng bộ đệm và họ viết tiêu chuẩn một khi bộ đệm được lấp đầy, nhưng không có đề cập nào về việc Nhà sản xuất-Người tiêu dùng phải tuân theo quy tắc đó - chỉ chờ khi hàng đợi được lấp đầy hoặc loại bỏ dữ liệu (đó là một cái gì đó khác mà đường ống không làm).

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.