Xử lý ống Bash


29

Có ai biết cách bash xử lý gửi dữ liệu qua đường ống không?

cat file.txt | tail -20 

Lệnh này có in tất cả nội dung của tệp.txt vào bộ đệm, sau đó đọc theo đuôi không? Hoặc thực hiện lệnh này, nói, in nội dung của dòng file.txt theo dòng, và sau đó tạm dừng ở mỗi dòng để đuôi xử lý, và sau đó yêu cầu thêm dữ liệu?

Lý do tôi hỏi là tôi đang viết chương trình trên thiết bị nhúng về cơ bản thực hiện chuỗi hoạt động trên một số đoạn dữ liệu, tại đó đầu ra của một thao tác được gửi đi làm đầu vào của thao tác tiếp theo. Tôi muốn biết làm thế nào Linux (bash) xử lý này vì vậy xin vui lòng cho tôi một câu trả lời chung, không cụ thể những gì sẽ xảy ra khi tôi chạy "cat file.txt | tail -20".

Cảm ơn bạn đã trả lời!

EDIT: Shog9 chỉ ra một Điều Wikipedia có liên quan, điều này đã không dẫn tôi trực tiếp đến bài viết nhưng nó đã giúp tôi tìm thấy điều này: http://en.wikipedia.org/wiki/Pipeline_%28Unix%29#Implementation đã có thông tin tôi đang tìm kiếm.


Tôi rất tiếc vì đã không làm rõ. Tất nhiên bạn đang sử dụng một đường ống và tất nhiên bạn đang sử dụng stdin và stdout của các phần tương ứng của lệnh. Tôi đã giả định rằng quá rõ ràng với trạng thái.

Điều tôi đang hỏi là cách xử lý/triển khai này. Vì cả hai chương trình không thể chạy cùng một lúc, dữ liệu được gửi từ stdin đến stdout như thế nào? Điều gì sẽ xảy ra nếu chương trình đầu tiên tạo ra dữ liệu nhanh hơn đáng kể so với chương trình thứ hai? Liệu hệ thống có chạy lệnh đầu tiên cho đến khi nó chấm dứt hoặc bộ đệm stdout đầy, rồi chuyển sang chương trình tiếp theo, và cứ như vậy trong vòng lặp cho đến khi không còn dữ liệu nào được xử lý hoặc có một cơ chế phức tạp hơn ?

54

Tôi quyết định viết giải thích chi tiết hơn một chút.

"ma thuật" ở đây nằm trong hệ điều hành. Cả hai chương trình đều khởi động cùng lúc và chạy cùng lúc (hệ điều hành gán cho chúng các lát thời gian trên bộ xử lý chạy) như mọi quá trình chạy đồng thời khác trên máy tính của bạn (bao gồm cả ứng dụng đầu cuối và hạt nhân) . Vì vậy, trước khi bất kỳ dữ liệu nào được truyền, các quy trình đang thực hiện bất kỳ việc khởi tạo nào cần thiết. Trong ví dụ của bạn, đuôi phân tích đối số '-20' và con mèo đang phân tích đối số 'file.txt' và mở tệp. Tại một số điểm đuôi sẽ nhận được đến điểm mà nó cần đầu vào và nó sẽ cho hệ điều hành biết rằng nó đang chờ đầu vào. Tại một số điểm khác (hoặc trước hoặc sau, nó không quan trọng) mèo sẽ bắt đầu truyền dữ liệu đến hệ điều hành bằng cách sử dụng stdout. Điều này đi vào một bộ đệm trong hệ điều hành. Đuôi thời gian tiếp theo nhận được một lát thời gian trên bộ xử lý sau khi một số dữ liệu đã được đưa vào bộ đệm bởi con mèo, nó sẽ lấy một lượng dữ liệu đó (hoặc tất cả) để lại bộ đệm trên hệ điều hành. Khi bộ đệm trống, tại một số điểm đuôi sẽ phải chờ cho mèo xuất nhiều dữ liệu hơn. Nếu con mèo xuất dữ liệu nhanh hơn nhiều so với đuôi thì nó sẽ mở rộng.mèo cuối cùng sẽ được thực hiện xuất dữ liệu, nhưng đuôi vẫn sẽ được xử lý, vì vậy mèo sẽ đóng và đuôi sẽ xử lý tất cả dữ liệu còn lại trong bộ đệm. Hệ điều hành sẽ báo hiệu đuôi khi chúng không còn dữ liệu đến với EOF. Tail sẽ xử lý dữ liệu còn lại. Trong trường hợp này, đuôi có lẽ chỉ nhận được tất cả dữ liệu vào một bộ đệm tròn 20 dòng, và khi nó được báo hiệu bởi hệ điều hành không có thêm dữ liệu đến, nó sẽ đổ hai mươi dòng cuối cùng vào stdout của riêng nó, chỉ được hiển thị trong thiết bị đầu cuối. Kể từ đuôi là một chương trình đơn giản hơn nhiều so với con mèo, nó có thể sẽ dành phần lớn thời gian chờ đợi cho mèo để đưa dữ liệu vào bộ đệm.

Trên một hệ thống có nhiều bộ xử lý, hai chương trình sẽ không chỉ chia sẻ các lát thời gian xen kẽ trên cùng một lõi bộ xử lý, nhưng có khả năng chạy cùng lúc trên các lõi riêng biệt.

Để xem chi tiết hơn, nếu bạn mở một số loại trình theo dõi (hệ điều hành cụ thể) như 'top' trong Linux, bạn sẽ thấy toàn bộ danh sách các quy trình đang chạy, phần lớn trong số đó đang sử dụng hiệu quả 0% bộ xử lý. Hầu hết các ứng dụng, trừ khi họ đang crunching dữ liệu, dành phần lớn thời gian của họ không làm gì cả. Điều này là tốt, bởi vì nó cho phép các quá trình khác có quyền truy cập không bị giới hạn vào bộ vi xử lý theo nhu cầu của họ. Điều này được thực hiện theo ba cách cơ bản. Một quá trình có thể nhận được một lệnh sleep (n) phong cách, nơi nó về cơ bản nói với hạt nhân để chờ đợi n mili giây trước khi cho nó một lát thời gian để làm việc với. Phổ biến nhất một chương trình cần phải chờ đợi một cái gì đó từ một chương trình khác, như 'đuôi' chờ đợi nhiều dữ liệu hơn để vào bộ đệm. Trong trường hợp này, hệ điều hành sẽ đánh thức quy trình khi có nhiều dữ liệu hơn. Cuối cùng, hạt nhân có thể preempt một quá trình ở giữa thực hiện, đưa ra một số lát thời gian xử lý cho các quá trình khác. 'cat' và 'tail' là các chương trình đơn giản. Trong ví dụ này, đuôi dành phần lớn thời gian chờ đợi nhiều dữ liệu hơn trên bộ đệm và mèo dành phần lớn thời gian chờ hệ điều hành truy xuất dữ liệu từ đĩa cứng. Nút cổ chai là tốc độ (hoặc chậm) của phương tiện vật lý mà tệp được lưu trữ. Sự chậm trễ nhận thức mà bạn có thể phát hiện khi bạn chạy lệnh này lần đầu tiên là thời gian cần thiết cho đầu đọc trên ổ đĩa để tìm vị trí trên ổ đĩa cứng có 'file.txt'. Nếu bạn chạy lệnh này lần thứ hai, hệ điều hành có thể sẽ chứa nội dung của file.txt được lưu trữ trong bộ nhớ, và bạn sẽ không thấy bất kỳ độ trễ nhận biết nào (trừ khi file.txt là rất lớn hoặc tệp không còn được lưu trữ nữa .)

Hầu hết các thao tác bạn thực hiện trên máy tính đều bị ràng buộc IO, tức là bạn thường chờ dữ liệu đến từ ổ cứng hoặc từ thiết bị mạng, v.v.


0

mèo sẽ chỉ in dữ liệu ra tiêu chuẩn, điều này sẽ được chuyển hướng đến tiêu chuẩn ở đuôi. Điều này có thể được nhìn thấy trong trang người đàn ông của bash.

Nói cách khác, không có tạm dừng đang diễn ra, đuôi chỉ đọc từ tiêu chuẩn và mèo chỉ viết thành tiêu chuẩn.


1

Shog9 đã tham chiếu bài viết trên Wikipedia, nhưng implementation section có các chi tiết bạn muốn. Việc thực hiện cơ bản là một bộ đệm bị chặn.