Tại sao một vòng lặp while dừng lại sau khi bị đình chỉ?


10

Tại sao sử dụng bash và tạm dừng một vòng lặp while, vòng lặp dừng lại sau khi được nối lại? Ví dụ ngắn dưới đây.

$ while true; do echo .; sleep 1; done
.
.
^Z
[1]+  Stopped                 sleep 1
$ fg
sleep 1
$

Tôi quen thuộc với các tín hiệu và tôi đoán đây có thể là hành vi tự nhiên của bash ở đây, nhưng tôi muốn hiểu rõ hơn tại sao nó hoạt động theo cách đặc biệt này.


bởi vì nó phải xử lý một ngắt và phải phản ánh chính xác rằng $?khi trả lại, và truesau đó thì không true. có lẽ. tôi nghĩ.
mikeerv

1
Tôi hy vọng bình luận này không bị gắn cờ, nhưng tôi sẽ trả lời câu hỏi của bạn bằng một câu hỏi khác, kiểu công án Unix: "Tại sao một học sinh ngừng chiến đấu trên sân chơi sau khi anh ta bị đình chỉ?" Câu trả lời là, bởi vì anh ta không còn ở sân chơi nơi anh ta có khả năng bắt đầu chiến đấu. Do đó, hành vi trong câu hỏi chỉ đơn giản là bị dừng lại.
rubynorails

Bạn dừng lệnh, vòng lặp bị hỏng. Sau đó, bạn tiếp tục lệnh ngủ đơn 1, không phải vòng lặp.
123

Câu trả lời:


10

Điều này trông giống như một lỗi trong một số shell, nó hoạt động như mong đợi với ksh93zsh .

Lý lịch:

Hầu hết các shell dường như chạy vòng lặp while bên trong shell chính và

Bourne Shell treo toàn bộ shell nếu bạn gõ ^ Z với shell không đăng nhập

Bash chỉ tạm dừng sleepvà sau đó rời khỏi vòng lặp while để in dấu nhắc shell mới

dấu gạch ngang làm cho lệnh này không được phép

Với ksh93 , mọi thứ hoạt động rất khác nhau:

ksh93 cũng làm như vậy, trong khi lệnh được bắt đầu lần đầu tiên, nhưng như sleeplà một buitin trong ksh93, ksh93 có một trình xử lý khiến vòng lặp while tách khỏi lớp vỏ chính và sau đó tạm dừng khi bạn gõ ^ Z.

Nếu bạn ở ksh93 loại sau fg, con bị tắt mà vẫn chạy vòng lặp được tiếp tục.

Bạn thấy sự khác biệt chính khi so sánh các thông báo công việc từ bash và ksh93:

báo cáo bash :

[1]+ Stopped sleep 1

nhưng báo cáo ksh93 :

^Z[1] + Stopped while true; do echo .; sleep 1; done

zsh hành xử tương tự như ksh93

Với cả hai shell, bạn có một tiến trình duy nhất (shell chính) miễn là bạn không gõ ^ Z và hai tiến trình shell sau khi bạn nhập ^ Z.


không dashthực sự kết thúc việc xử lý tín hiệu khi vòng lặp kết thúc? trong [d]?ashmã nguồn, có tất cả các macro cho INTONINTOFF phân tán trong suốt và thông thường các tín hiệu nhận được khi ở trạng thái INTOFF thực sự được xử lý tại (hoặc xung quanh) INTON . Dù sao, tôi chỉ tò mò vì tôi nghĩ bạn biết rõ hơn - đó là một câu trả lời tuyệt vời. cảm ơn bạn.
mikeerv

Tôi hiếm khi sử dụng dấu gạch ngang và gần đây tôi đã tìm nạp và biên dịch nó để so sánh hiệu suất với bash, ksh93 và Bourne Shell của tôi. Trong khi thực hiện các thử nghiệm này, tôi phát hiện ra rằng dấu gạch ngang chủ yếu có vẻ nhanh vì nó không bao gồm hỗ trợ cho các ký tự nhiều byte. Một đơn sleep 100có thể bị đình chỉ và tiếp tục dash, vì vậy có vẻ như dashbiết về các vấn đề trong lệnh này và vô hiệu hóa chọn lọc kiểm soát công việc.
schily

Vì vậy, trong các thử nghiệm của bạn, bạn có thể cân bằng dashhiệu suất của các vỏ khác bằng cách bỏ quá trình xử lý đa bào? và vâng, dashkhông hỗ trợ kiểm soát công việc, nhưng tiêu chuẩn nói rằng một vỏ tương tác nên bỏ qua TSTP và chạy một vòng lặp while trong trình bao hiện tại tại một thiết bị đầu cuối tương tác không kém gì một vỏ tương tác.
mikeerv

Tôi đã không kiểm tra chính xác điều này, nhưng tôi có thể thấy rằng trong khi dash tiêu tốn nhiều thời gian CPU hệ thống hơn ksh93 hoặc Bourne Shell (chủ yếu vì nó thực hiện nhiều cuộc gọi fork () hơn), nó sử dụng ít thời gian CPU của người dùng hơn và điều này dẫn đến tổng số tương tự Thời gian CPU so với phiên bản Bourne Shell của tôi. Từ việc cố gắng giảm thời gian CPU của người dùng trong Bourne Shell, tôi biết rằng phần lớn thời gian này là dành cho chuyển đổi đa nhân.
schily

4

Tôi đã viết một trong những đồng tác giả của Bash về vấn đề này, và đây là câu trả lời của anh ấy:

Nó không thực sự là một lỗi, nhưng nó chắc chắn là một cảnh báo.

Ý tưởng ở đây là bạn tạm dừng các quá trình, là một đơn vị chi tiết khác với các lệnh shell. Khi một quá trình bị đình chỉ, nó sẽ trở về trình bao (với trạng thái khác không, có hậu quả khi bạn nói, dừng một quá trình đó là kiểm tra vòng lặp), có một lựa chọn: nó có thể thoát ra hoặc tiếp tục vòng lặp , để lại quá trình dừng lại phía sau. Bash chọn - và luôn luôn chọn - để thoát ra khỏi các vòng lặp khi công việc bị dừng lại. Tiếp tục vòng lặp hiếm khi bạn muốn.

Một số shell khác thực hiện những việc như fork một bản sao của shell khi một tiến trình bị đình chỉ do SIGTSTP và dừng quá trình đó. Bash chưa bao giờ làm điều đó - có vẻ phức tạp hơn các lệnh bảo đảm lợi ích - nhưng nếu ai đó muốn gửi mã đó dưới dạng bản vá, tôi sẽ xem xét kết hợp các thay đổi.

Vì vậy, nếu bất cứ ai muốn gửi một bản vá, hãy sử dụng các địa chỉ email được tìm thấy trong các trang man.

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.