Làm thế nào để hiểu đường ống


21

Khi tôi chỉ sử dụng đường ống trong bash, tôi đã không nghĩ nhiều hơn về điều này. Nhưng khi tôi đọc một số ví dụ mã C sử dụng ống gọi hệ thống () cùng với fork (), tôi tự hỏi làm thế nào để hiểu các đường ống, bao gồm cả đường ống ẩn danh và đường ống có tên.

Người ta thường nghe nói rằng "mọi thứ trong Linux / Unix là một tệp". Tôi tự hỏi nếu một đường ống thực sự là một tập tin để một phần mà nó kết nối ghi vào tập tin đường ống, và phần khác đọc từ tập tin đường ống? Nếu có, tập tin đường ống cho một đường ống ẩn danh được tạo ở đâu? Trong / tmp, / dev hoặc ...?

Tuy nhiên, từ các ví dụ về các đường ống được đặt tên, tôi cũng học được rằng việc sử dụng các đường ống có lợi thế về hiệu suất không gian và thời gian so với việc sử dụng các tệp tạm thời một cách rõ ràng, có lẽ vì không có tệp nào liên quan đến việc thực hiện các đường ống. Ngoài ra các đường ống dường như không lưu trữ dữ liệu như các tập tin làm. Vì vậy, tôi nghi ngờ một đường ống thực sự là một tập tin.

Câu trả lời:


23

Về câu hỏi về hiệu suất của bạn, các đường ống hiệu quả hơn các tệp vì không cần IO đĩa. Vì vậy, cmd1 | cmd2hiệu quả hơn cmd1 > tmpfile; cmd2 < tmpfile(điều này có thể không đúng nếu tmpfileđược hỗ trợ trên đĩa RAM hoặc thiết bị bộ nhớ khác như ống có tên; nhưng nếu đó là ống có tên, cmd1thì nên chạy trong nền vì đầu ra của nó có thể chặn nếu đường ống đầy ). Nếu bạn cần kết quả cmd1và vẫn cần gửi đầu ra của nó tới cmd2, bạn cmd1 | tee tmpfile | cmd2sẽ cho phép cmd1cmd2chạy song song tránh các hoạt động đọc đĩa từ đó cmd2.

Các ống được đặt tên là hữu ích nếu nhiều quá trình đọc / ghi vào cùng một ống. Chúng cũng có thể hữu ích khi một chương trình không được thiết kế để sử dụng stdin / stdout cho IO cần sử dụng tệp . Tôi đặt các tệp in nghiêng vì các ống có tên không phải là các tệp chính xác theo quan điểm lưu trữ vì chúng nằm trong bộ nhớ và có kích thước bộ đệm cố định, ngay cả khi chúng có mục hệ thống tệp (cho mục đích tham khảo). Những thứ khác trong UNIX có các mục hệ thống tệp mà không phải là tệp: chỉ cần nghĩ đến /dev/nullhoặc các mục khác trong /devhoặc /proc.

Vì các đường ống (được đặt tên và không được đặt tên) có kích thước bộ đệm cố định, các hoạt động đọc / ghi đối với chúng có thể chặn, khiến quá trình đọc / ghi diễn ra ở trạng thái IOWait. Ngoài ra, khi nào bạn nhận được EOF khi đọc từ bộ nhớ đệm? Các quy tắc về hành vi này được xác định rõ và có thể được tìm thấy ở người đàn ông.

Một điều bạn không thể làm với các đường ống (được đặt tên và không được đặt tên) là tìm kiếm lại dữ liệu. Khi chúng được thực hiện bằng cách sử dụng bộ nhớ đệm, điều này là dễ hiểu.

Về "everything in Linux/Unix is a file", tôi không đồng ý. Các ống được đặt tên có các mục hệ thống tập tin, nhưng không chính xác tập tin. Các ống không tên không có các mục hệ thống tập tin (ngoại trừ có thể trong /proc). Tuy nhiên, hầu hết các hoạt động IO trên UNIX đều được thực hiện bằng cách sử dụng chức năng đọc / ghi cần một bộ mô tả tệp , bao gồm cả đường ống không tên (và ổ cắm). Tôi không nghĩ rằng chúng ta có thể nói điều đó "everything in Linux/Unix is a file", nhưng chúng ta chắc chắn có thể nói điều đó "most IO in Linux/Unix is done using a file descriptor".


Cảm ơn! Có phải hai lệnh được kết nối bởi một đường ống chạy song song, thay vì lệnh thứ hai bắt đầu chạy sau khi kết thúc lần đầu tiên?
Tim

Có, 2 lệnh được chạy song song. Nếu chúng không và đầu ra thứ 1 nhiều hơn bộ đệm, nó sẽ bị chặn. Bạn có thể thử nó bằng cách chạy cmd1 > fifocmd2 < fifotrong 2 shell khác nhau, tạo đường ống có tên mkfifo fifo.
jfg956

Một thử nghiệm khác bạn có thể làm, là giết cmd2trong khi cmd1vẫn đang chạy: cmd1có thể sẽ ngừng báo cáo một mesage ống bị hỏng.
jfg956

Cảm ơn! ý bạn là gì sẽ bị chặn? Nếu điều này xảy ra, điều đó có nghĩa là ngày trong luồng sau khối sẽ bị mất?
Tim

2
Dữ liệu không bị mất. Nếu bộ đệm ống đầy, cmd1ghi vào đường ống sẽ chỉ trở lại khi cmd2có dữ liệu đọc từ đường ống. Theo cùng một cách, cmd2đọc từ một đường ống sẽ chặn nếu bộ đệm trống cho đến khi cmd1ghi vào đường ống.
jfg956

4

Hai trong số các nguyên tắc cơ bản của triết học UNIX là

  1. Để làm cho các chương trình nhỏ làm một điều tốt.
  2. và hy vọng đầu ra của mọi chương trình sẽ trở thành đầu vào cho chương trình khác, như
    chưa biết, chương trình.

    Việc sử dụng các đường ống cho phép bạn tận dụng các hiệu ứng của hai
    nguyên tắc cơ bản thiết kế này để tạo ra các chuỗi lệnh cực kỳ mạnh mẽ để đạt được kết quả mong muốn của bạn.

    Hầu hết các chương trình dòng lệnh hoạt động trên các tệp cũng có thể chấp nhận đầu vào trên tiêu chuẩn trong (đầu vào thông qua bàn phím) và xuất ra tiêu chuẩn (in trên
    màn hình).

    Một số lệnh được thiết kế để chỉ hoạt động trong một đường ống không thể hoạt động trực tiếp trên các tệp.

    ví dụ trlệnh

  ls -C | tr 'a-z' 'A-Z'
    cmd1 | cmd2
  • Gửi STDOUT của cmd1 đến STDIN của cmd2 thay vì màn hình.

  • STDERR không được chuyển tiếp qua các đường ống.

    Trong ngắn hạn Pipes is character (|)có thể kết nối các lệnh.

    Bất kỳ lệnh nào ghi vào STDOUT có thể được sử dụng ở phía bên trái của đường ống.

       ls - /etc | less 

    Bất kỳ lệnh nào đọc từ STDIN đều có thể được sử dụng ở phía bên phải của đường ống.

       echo "test print" | lpr 

    Một đường ống truyền thống là "không tên" bởi vì nó tồn tại ẩn danh và chỉ tồn tại trong chừng nào quá trình đang chạy. Một ống có tên là bền vững hệ thống và tồn tại ngoài vòng đời của quy trình và phải được xóa sau khi nó không còn được sử dụng. Các quy trình thường gắn vào đường ống có tên (thường xuất hiện dưới dạng tệp) để thực hiện giao tiếp giữa các quá trình (IPC).

nguồn: http://en.wikipedia.org/wiki/Named_pipe


3

Để bổ sung cho các câu trả lời khác ...

stdin và stdout là các mô tả tệp và được đọc và viết như thể chúng là các tệp. do đó bạn có thể làm echo hi | grep hi, và nó sẽ thay thế thiết bị xuất chuẩn của echo bằng một đường ống và thay thế stdin của grep sang đầu kia của đường ống này.


1

Tất cả mọi thứ là một tập tin.

Nếu chúng ta sử dụng cụm từ quá đúng theo nghĩa đen, chúng ta sẽ có nghĩa là chúng ta chỉ có các tệp và không có gì khác. Đây không phải là giải thích chính xác, vì vậy những gì là.

Khi chúng tôi nói rằng Mọi thứ đều là một tập tin, chúng tôi không nói rằng mọi thứ được lưu trữ trên đĩa. Chúng tôi đang nói rằng mọi thứ trông giống như một tập tin, có thể được đọc, có thể được viết.

Trong Unix, một khi một tệp hoặc không phải tệp được mở, thì nó có thể được coi như một tệp. Tuy nhiên không phải tất cả các tập tin hỗ trợ tất cả các hoạt động. Ví dụ: một số tệp (không phải là tệp), không hỗ trợ tìm kiếm: chúng phải được đọc / ghi theo trình tự (điều này đúng với đường ống và ổ cắm).

Mọi thứ đều có tên tệp (trên một số hệ thống: ví dụ: Debian Gnu / Linux và nhiều Gnu / Linux khác).

  • Tất cả các tệp đang mở có được một tên tệp. Xem/proc/self/fd/…
  • Ổ cắm mạng có thể được mở bằng tên tệp, /dev/tcp
    ví dụ:cat </dev/tcp/towel.blinkenlights.nl/23

Phần cuối cùng đó chỉ hợp lệ trên các hệ thống có /prochệ thống tệp và trên các hệ thống (hoặc hệ vỏ) cung cấp /dev/tcpcấu trúc tệp.
Kusalananda
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.