Ống là một tệp được mở trong một hệ thống tệp trong kernel và không thể truy cập như một tệp thông thường trên đĩa. Nó được tự động đệm chỉ đến một kích thước nhất định và cuối cùng sẽ chặn khi đầy. Không giống như các tệp có nguồn gốc trên các thiết bị khối, các đường ống hoạt động rất giống các thiết bị ký tự và do đó thường không hỗ trợ lseek()
và dữ liệu đọc từ chúng không thể được đọc lại như bạn có thể làm với một tệp thông thường.
Chuỗi ở đây là một tệp thông thường được tạo trong một hệ thống tệp được gắn kết. Shell tạo tệp và giữ lại bộ mô tả của nó trong khi ngay lập tức xóa liên kết hệ thống tệp duy nhất của nó (và xóa nó) trước khi nó ghi / đọc một byte đến / từ tệp. Nhân sẽ duy trì không gian cần thiết cho tệp cho đến khi tất cả các quy trình giải phóng tất cả các mô tả cho nó. Nếu đứa trẻ đọc từ một mô tả như vậy có khả năng để làm điều đó, nó có thể được lseek()
đọc lại và đọc lại.
Trong cả hai trường hợp, mã thông báo <<<
và |
đại diện cho mô tả tệp và không nhất thiết phải là chính các tệp. Bạn có thể hiểu rõ hơn về những gì đang diễn ra bằng cách làm những việc như:
readlink /dev/fd/1 | cat
...hoặc là...
ls -l <<<'' /dev/fd/*
Sự khác biệt đáng kể nhất giữa hai tệp là chuỗi-doc ở đây gần như là một vấn đề tất cả cùng một lúc - trình bao ghi tất cả dữ liệu vào đó trước khi đưa ra mô tả đọc cho trẻ. Mặt khác, vỏ mở đường ống trên các mô tả thích hợp và tách trẻ em ra để quản lý chúng cho đường ống - và do đó, nó được viết / đọc đồng thời ở cả hai đầu.
Những sự phân biệt này, mặc dù, chỉ nói chung là đúng. Theo như tôi biết (điều này thực sự không xa lắm) thì điều này đúng với hầu hết mọi vỏ xử lý <<<
chuỗi ngắn <<
ở đây để chuyển hướng tài liệu ở đây với ngoại lệ duy nhất yash
. yash
, busybox
, dash
, Và các ash
biến thể có xu hướng trở lại đây-tài liệu với đường ống, tuy nhiên, và vì vậy trong những vỏ có thực sự là rất ít sự khác biệt giữa hai sau khi tất cả.
Ok - hai ngoại lệ. Bây giờ tôi đang nghĩ về nó, ksh93
thực tế không phải là một ống cho tất cả |
, mà là xử lý toàn bộ w / socket của doanh nghiệp - mặc dù nó làm một tệp tmp bị xóa <<<*
như hầu hết những người khác làm. Hơn nữa, nó chỉ đặt các phần riêng biệt của một đường ống trong môi trường lớp dưới , đó là một loại uyển ngữ POSIX cho ít nhất là nó hoạt động như một lớp con , và do đó thậm chí không thực hiện các nhánh.
Thực tế là kết quả điểm chuẩn của @ PSkocik (rất hữu ích) ở đây có thể rất khác nhau vì nhiều lý do và hầu hết trong số này phụ thuộc vào việc thực hiện. Đối với thiết lập tài liệu ở đây, các yếu tố lớn nhất sẽ là ${TMPDIR}
loại hệ thống tệp mục tiêu và cấu hình / tính khả dụng của bộ đệm hiện tại và vẫn còn lưu lượng dữ liệu được ghi. Đối với đường ống, nó sẽ là kích thước của quá trình vỏ, bởi vì các bản sao được tạo ra cho các dĩa yêu cầu. Theo cách bash
này là khủng khiếp khi thiết lập đường ống (bao gồm cả thay thế $(
lệnh )
) - bởi vì nó lớn và rất chậm, nhưng với ksh93
nó hầu như không có sự khác biệt nào cả.
Đây là một đoạn vỏ nhỏ khác để giải thích cách một vỏ tách ra khỏi các lớp con cho một đường ống:
pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0
32059 #bash's pid
32059 #sh's ppid
32059 #1st subshell's $$
32111 #1st subshell sh's ppid
32059 #2cd subshell's $$
32114 #2cd subshell sh's ppid
Sự khác biệt giữa những gì một pipe_who()
báo cáo cuộc gọi theo đường ống và báo cáo về một lần chạy trong lớp vỏ hiện tại là do hành vi được chỉ định (
của một lớp con )
trong việc yêu cầu pid của vỏ cha mẹ $$
khi nó được mở rộng. Mặc dù các bash
lớp con chắc chắn là các quá trình riêng biệt, $$
tham số shell đặc biệt không phải là nguồn đáng tin cậy của thông tin này. Tuy nhiên, lớp vỏ con của sh
lớp con không từ chối báo cáo chính xác $PPID
.