Có an toàn không khi nhập một lệnh khác vào STDIN trong khi lệnh trước đó đang ghi vào STDOUT?


21

Có lẽ điều này đã được trả lời trước đây, tôi sẽ hoan nghênh một liên kết đến một câu trả lời khác ...

Nếu tôi thực thi lệnh shell (trong bashshell) như sau:

make

Sau đó, trong khi sản lượng từ makeđược di chuyển bằng từ STDOUTcủa makelệnh, nếu tôi gõ make checkvà nhấn entertrước khi lệnh đầu tiên được hoàn tất thi công, khi makelệnh cuối cùng kết thúc lệnh tiếp theo make checklên ngay và chạy sẽ đón.

Câu hỏi của tôi chỉ đơn giản là:

  1. Điều này có nguy hiểm không?
  2. Có bất kỳ hành vi bất ngờ tiềm năng từ loại gõ vội vàng này?
  3. Tại sao điều này hoạt động theo cách nó làm?

2
1. Tôi hy vọng nó không ... Tôi đã làm điều này trong nhiều năm!
John WH Smith

Câu trả lời:


20

Nó hoạt động theo cách của nó bởi vì Unix là song công hoàn toàn. Như Ritchie đã nói trong Hệ thống chia sẻ thời gian UNIX: Hồi tưởng :

Một điều có vẻ tầm thường, nhưng lại tạo ra sự khác biệt đáng ngạc nhiên khi người ta đã quen với nó, đó là I / O đầu cuối song công hoàn toàn cùng với đọc trước. Mặc dù các chương trình thường giao tiếp với người dùng về các dòng, thay vì các ký tự đơn, I / O của thiết bị song công hoàn toàn có nghĩa là người dùng có thể nhập bất cứ lúc nào, ngay cả khi hệ thống đang gõ lại, mà không sợ mất hoặc cắt xén các ký tự . Với việc đọc trước, người ta không cần chờ phản hồi cho mỗi dòng. Một người đánh máy giỏi nhập một tài liệu trở nên cực kỳ thất vọng khi phải tạm dừng trước khi bắt đầu mỗi dòng mới; cho bất cứ ai biết những gì anh ta muốn nói bất kỳ sự chậm chạp trong phản ứng sẽ trở nên phóng đại về mặt tâm lý nếu thông tin phải được nhập từng chút một thay vì ở tốc độ tối đa.

[trích dẫn cuối]

Điều đó đang được nói, có một số chương trình hiện đại ăn lên hoặc loại bỏ bất kỳ kiểu chữ nào; sshapt-getlà hai ví dụ. Nếu bạn nhập trước khi họ đang chạy, bạn có thể thấy rằng phần đầu tiên của đầu vào của bạn đã biến mất. Đó có thể là một vấn đề.

ssh remotehost do something that takes 20 seconds
mail bob
Dan has retired. Feel free to save any important files and then do
# ssh exits here, discarding the previous 2 lines
rm -fr *
.

Vậy sau lệnh bash fork()s và execs, lệnh đầu tiên có còn được gắn vào STDINbash shell không? Có vẻ như câu trả lời là không, bash dường như sẽ được đệm cho lệnh tiếp theo. Đúng không?
111 ---

Trừ khi bạn nói với shell để chuyển hướng stdin của lệnh, lệnh sẽ có cùng stdin với shell. Bất cứ điều gì bạn gõ được đọc bởi quá trình đầu tiên đọc nó. Shell cố tình không cố đọc bất cứ thứ gì trong khi một lệnh đang chạy và đợi cho đến khi lệnh dừng lại. Mọi thứ trở nên phức tạp hơn nếu bạn đặt lệnh trong nền với &.
Đánh dấu Plotnick

Vì vậy, được STDINxử lý một cách fifo? Và tôi cho rằng trừ khi quá trình bash con đóng hoàn toàn xử lý tệp được kế thừa của nó để STDINnó vẫn có thể đọc được từ việc gõ bổ sung?
111 ---

Có, tất cả các đầu vào thiết bị đầu cuối được xử lý FIFO. Không chắc chắn tôi hiểu câu hỏi thứ hai của bạn. Quá trình con - lệnh mà shell đã gọi - thường không đóng stdin của nó một cách rõ ràng; Shell bước ra khỏi đường và cho phép lệnh đọc tất cả những gì nó muốn, sau đó đứa trẻ dừng lại và shell tiếp tục đọc.
Đánh dấu Plotnick

Vâng, bạn đã giải quyết cả hai câu hỏi tiếp theo của tôi rất rõ ràng, cảm ơn!
111 ---

12

Hành vi cơ bản mà bạn nhìn thấy là đầu vào nằm trong một bộ đệm ở đâu đó cho đến khi nó đọc (tốt, nếu bạn nhập đủ, cuối cùng bộ đệm sẽ lấp đầy, và một cái gì đó sẽ bị mất, mặc dù vậy sẽ rất nhiều gõ). Hầu hết mọi thứ chạy bằng cách không đọc từ STDIN, vì vậy nó nằm trong bộ đệm.

Điều nguy hiểm là lệnh sai đọc đầu vào của bạn. Ví dụ, makegọi một cái gì đó quyết định nhắc bạn, và sau đó nó có thể đọc lệnh tiếp theo của bạn như một câu trả lời. Làm thế nào nguy hiểm đó là phụ thuộc vào lệnh, tất nhiên. (Họ cũng có thể xóa tất cả đầu vào trước, chỉ cần loại bỏ đầu vào trước đó của bạn.)

Một lệnh, thường được sử dụng trong Makefiles, có thể làm điều đó là TeX. Nếu nó gặp lỗi (và chưa được cấp cờ để không bao giờ nhắc người dùng), nó sẽ nhắc bạn muốn tiếp tục như thế nào.

Một lựa chọn tốt hơn có lẽ là để chạy : make && make check.


8
  1. Chà, rõ ràng, bạn không nên chạy lệnh thứ hai phụ thuộc vào lệnh đầu tiên ( make, trong ví dụ của bạn) đã hoàn thành thành công. Ví dụ, make foo Enter> ./foo Enter có thể gây ra vấn đề. Bạn có thể muốn thử tập thói quen gõ những thứ như make && make check, trong đó lệnh thứ hai sẽ chỉ được thực hiện nếu lệnh đầu tiên thành công.
  2. Về mặt lý thuyết có thể là lệnh đầu tiên (process (es)) có thể đọc một phần của lệnh thứ hai, hoặc loại bỏ nó khỏi bộ đệm đầu vào đầu cuối. Nếu nó ăn sáu ký tự đầu tiên make check, cuối cùng bạn sẽ thực thi lệnh heck, có lẽ không tồn tại trên hệ thống của bạn (nhưng có thể là một cái gì đó khó chịu). Nếu lệnh đầu tiên là thứ gì đó lành tính mà bạn biết và tin tưởng, tôi sẽ không thấy ngay bất kỳ vấn đề nào.
  3. Làm thế nào / tại sao nó hoạt động? Hệ thống đệm đầu vào bàn phím. Nó giống như e-mail: bạn có thể gửi cho một người năm tin nhắn trong một khoảng thời gian ngắn và họ sẽ ngồi trong Hộp thư đến của anh ấy, chờ anh ấy đọc chúng. Tương tự, miễn là lệnh đầu tiên không đọc từ bàn phím, (các) lệnh mà bạn nhập sẽ ngồi và đợi trình bao đi xung quanh để đọc chúng. Có một giới hạn về mức độ có thể được đệm trước nhiều kiểu của Viking, nhưng nó thường là vài trăm ký tự (nếu không phải là vài nghìn).

2
Đến điểm 1, hãy tưởng tượng rằng các lệnh không liên quan, ví dụ lsmountví dụ. Tôi đang cố gắng hiểu làm thế nào các đầu vào đệm được xử lý. Cảm ơn câu trả lời.
111 ---
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.