Đặt tên ống, mô tả tập tin và EOF


10

Hai cửa sổ, cùng một người dùng, với lời nhắc bash. Trong loại cửa sổ-1:

$ mkfifo f; exec <f

Vì vậy, bash hiện đang cố đọc từ mô tả tệp 0, được ánh xạ tới ống có tên f. Trong loại cửa sổ-2:

$ echo ls > f

Bây giờ window-1 in một ls và sau đó shell chết. Tại sao?

Thí nghiệm tiếp theo: mở cửa sổ-1 lần nữa với exec <f. Trong loại cửa sổ-2:

$ exec 3>f
$ echo ls >&3

Sau dòng đầu tiên ở trên, window-1 thức dậy và in dấu nhắc. Tại sao? Sau dòng thứ hai ở trên, window-1 in lsđầu ra và shell vẫn còn sống. Tại sao? Thực tế, bây giờ trong window-2, echo ls > fkhông đóng shell window-1.

Câu trả lời phải có liên quan đến sự tồn tại của bộ mô tả tệp 3 từ cửa sổ-2 tham chiếu đường ống có tên?!


1
Sau đó exec <f, bashkhông cố đọc từ fđầu, trước tiên là cố gắng mở nó. Các open()sẽ không trở lại cho đến khi có một số quá trình làm một nẻo mở trong chế độ ghi vào ống (lúc này đường ống sẽ được khởi tạo, và vỏ sẽ đọc thông tin từ nó).
Stéphane Chazelas

Điểm tuyệt vời, @ StéphaneChazelas. Đây phải là lý do tại sao, một khi exec 3>fđược chạy, shell đầu tiên sẽ đưa ra lời nhắc. (Điểm nhỏ, ý bạn là "trong chế độ ghi " trong bình luận của bạn?)
Fixee

1
Vâng xin lôi. Đã chỉnh sửa ngay trước thời hạn 5 phút
Stéphane Chazelas

Câu trả lời:


12

Nó phải làm với việc đóng bộ mô tả tập tin.

Trong ví dụ đầu tiên của bạn, echoghi vào luồng đầu ra tiêu chuẩn của nó mà shell mở ra để kết nối với nó fvà khi nó kết thúc, bộ mô tả của nó được đóng lại (bằng shell). Ở đầu nhận, shell, đọc đầu vào từ luồng đầu vào tiêu chuẩn (được kết nối với f) đọc ls, chạy lsvà sau đó chấm dứt do điều kiện cuối tệp trên đầu vào tiêu chuẩn của nó.

Điều kiện cuối tập tin xảy ra bởi vì tất cả các nhà văn của đường ống được đặt tên (chỉ một trong ví dụ này) đã đóng đầu ống của họ.

Trong ví dụ thứ hai của bạn, exec 3>fmở mô tả tệp 3 để ghi vào f, sau đó echoghi lsvào nó. Đó là trình bao giờ đã mở bộ mô tả tệp chứ không phải echolệnh. Các mô tả vẫn mở cho đến khi bạn làm exec 3>&-. Ở đầu nhận, shell, đọc đầu vào từ luồng đầu vào tiêu chuẩn của nó (được kết nối với f) đọc ls, chạy lsvà sau đó chờ thêm đầu vào (vì luồng vẫn mở).

Luồng vẫn mở vì tất cả các tác giả viết cho nó (shell, via exec 3>fecho) chưa đóng đầu ống của chúng ( exec 3>fvẫn còn hiệu lực).


Tôi đã viết echoở trên như thể đó là một lệnh bên ngoài. Nó rất có thể được tích hợp vào vỏ. Tuy nhiên, hiệu quả là như nhau.


6

Không có gì nhiều: khi không có người viết vào đường ống, nó sẽ đóng cho người đọc, tức là trả về EOF khi đọc và chặn khi mở.

Từ trang người dùng Linux ( pipe(7)nhưng cũng xem fifo(7)):

Nếu tất cả các mô tả tệp đề cập đến đầu ghi của một đường ống đã bị đóng, thì một nỗ lực read(2)từ đường ống sẽ thấy kết thúc của tệp ( read(2)sẽ trả về 0).

Đóng kết thúc ghi là những gì ngầm xảy ra ở cuối echo ls >fvà, như bạn nói, trong trường hợp khác, bộ mô tả tệp được giữ mở.


Có vẻ tương tự như số lượng tham chiếu trong Java (và các ngôn ngữ OO khác)! Làm cho ý nghĩa mặc dù.
Fixee

2

Sau khi đọc hai câu trả lời từ @Kusalananda và @ikkachu, tôi nghĩ tôi đã hiểu. Trong cửa sổ-1, vỏ đang chờ một cái gì đó vừa mở đầu ghi của ống rồi đóng lại. Khi kết thúc ghi được mở, trình bao trong cửa sổ-1 sẽ in một dấu nhắc. Khi kết thúc ghi, vỏ được EOF và chết.

Về phía cửa sổ-2, chúng ta có hai tình huống được mô tả trong câu hỏi của tôi: trong tình hình đầu tiên với echo ls > f, không có mô tả tập tin 3, vì vậy chúng tôi đã echosinh sản, và nó stdinstdoutcái nhìn như thế này:

0 --> tty
1 --> f

Sau đó echochấm dứt và vỏ đóng cả hai mô tả. Vì bộ mô tả tệp 1 được đóng và tham chiếu f, kết thúc ghi fđược đóng và điều đó gây ra EOF cho cửa sổ-1.

Trong tình huống thứ hai, chúng ta chạy exec 3>ftrong lớp vỏ của mình, khiến lớp vỏ mất môi trường này:

bash:
0 --> tty
1 --> tty
2 --> tty
3 --> f

Bây giờ chúng tôi chạy echo ls >& 3và shell phân bổ mô tả tệp echonhư sau:

echo:
0 --> tty
1 --> f     # because 3 points to f
2 --> tty

Sau đó, shell đóng ba mô tả ở trên, bao gồm f, nhưng fvẫn có một tham chiếu đến nó từ chính vỏ. Đây là sự khác biệt quan trọng. Đóng mô tả 3 với exec 3>&-sẽ đóng tham chiếu mở cuối cùng và gây ra EOF cho cửa sổ-1, như @Kusalananda lưu ý.


Đây là một ví dụ tốt về lý do tại sao bạn nên để ba mô tả tệp đầu tiên trừ khi có lý do thiết kế tốt để sửa đổi chúng. Khi bạn sử dụng bộ mô tả (1) cuối cùng là bộ mô tả đầu vào (0) cho lớp vỏ khác, bạn không chỉ đóng ống (và những gì bạn đang làm với luồng dữ liệu cụ thể đó), mà còn đóng đầu vào vào thứ hai vỏ khiến nó chấm dứt. Điều này tốt, nhưng chỉ khi bạn cố tình làm điều đó. Sử dụng các bộ mô tả tệp được đánh số cao hơn sẽ tránh được các tác dụng phụ như thế này vì không có gì mong đợi chúng ở bất kỳ trạng thái cụ thể nào hoặc thậm chí được xác định.
Joe

Thành thật mà nói, tôi không chắc những gì tôi đã cố gắng nói trong bình luận đó, tôi sẽ chỉ xóa nó.
Stéphane Chazelas
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.