Dlaczego pętla while zatrzymuje się po zawieszeniu?

10

Dlaczego po użyciu bash i zawieszeniu pętli while pętla zatrzymuje się po wznowieniu? Krótki przykład poniżej.

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

Znam sygnały i domyślam się, że może to być naturalne zachowanie basha, ale chciałbym lepiej zrozumieć, dlaczego tak się zachowuje.

BKZLAND
źródło
ponieważ musi obsłużyć przerwanie i musi dokładnie odzwierciedlić to $?po powrocie, i tak też truenie jest true. prawdopodobnie. Myślę.
mikeserv
1
Mam nadzieję, że ten komentarz nie zostanie oznaczony, ale odpowiem na inne pytanie, w stylu uniksowego stylu koan: „Dlaczego uczeń przestaje walczyć na placu zabaw po zawieszeniu?” Odpowiedź brzmi, ponieważ nie ma go już na placu zabaw, na którym ma możliwość rozpoczęcia walki. Tak więc omawiane zachowanie zostało po prostu zatrzymane.
rubynorails
Zatrzymaj polecenie, pętla zostanie zerwana. Następnie wznawiasz polecenie pojedynczego uśpienia 1, a nie pętlę.
123,
1
Odpowiedni
123

Odpowiedzi:

10

To wygląda jak błąd w kilku powłokach, działa zgodnie z oczekiwaniami z ksh93 i zsh .

Tło:

Większość pocisków wydaje się uruchamiać pętlę while wewnątrz głównej powłoki i

Bourne Shell zawiesza całą powłokę, jeśli wpiszesz ^ Z za pomocą powłoki niezalogowanej

bash zawiesza tylko, sleepa następnie pozostawia pętlę while na rzecz drukowania nowego polecenia powłoki

myślnik sprawia, że ​​polecenie to nie jest zawieszalne

Z ksh93 rzeczy działają zupełnie inaczej:

ksh93 robi to samo, gdy polecenie jest uruchamiane za pierwszym razem, ale jakosleep buitin w ksh93, ksh93 ma moduł obsługi, który powoduje, że pętla while rozwidla główną powłokę, a następnie zawiesza się podczas wpisywania ^ Z.

Jeśli wpiszesz w ksh93 później fg, rozwidlone dziecko, które nadal uruchamia pętlę, jest kontynuowane.

Widzisz główną różnicę podczas porównywania komunikatów kontroli zadań z bash i ksh93:

raporty bash :

[1]+ Stopped sleep 1

ale raporty ksh93 :

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

zsh zachowuje się podobnie do ksh93

W przypadku obu powłok masz jeden proces (główną powłokę), o ile nie wpiszesz ^ Z, i dwa procesy powłoki po wpisaniu ^ Z.

schily
źródło
tak dashnaprawdę nie kończy obsługi sygnału po zakończeniu pętli? w [d]?ashkodzie źródłowym są wszystkie te makra dla INTON i INTOFF rozproszone, i zazwyczaj sygnały odbierane w stanie INTOFF są obsługiwane w INTON (lub wokół niego) . w każdym razie jestem ciekaw, bo myślę, że wiesz lepiej - to świetna odpowiedź. Dziękuję Ci.
mikeserv
Rzadko używam myślnika, a ostatnio go pobrałem i skompilowałem do porównań wydajności z bash, ksh93 i moją Bourne Shell. Podczas wykonywania tych testów odkryłem, że myślnik wydaje się być szybki, ponieważ nie obsługuje znaków wielobajtowych. Pojedynczy sleep 100można zawiesić i wznowić dash, więc wydaje się, że dashwie o problemach z tym poleceniem i selektywnie wyłącza kontrolę zadań.
szczęśliwie
więc w swoich testach udało ci się zrównoważyć dashwydajność w innych powłokach, porzucając przetwarzanie wielobajtowe? i tak, dashobsługuje kontrolę zadań, ale standard mówi, że powłoka interaktywna powinna ignorować TSTP, a uruchomienie pętli while w bieżącej powłoce na terminalu interaktywnym jest nie mniej niż powłoką interaktywną.
mikeserv
Nie przetestowałem tego dokładnie, ale widziałem, że chociaż dash zużywa więcej czasu procesora systemowego niż ksh93 lub Bourne Shell (głównie dlatego, że wydaje więcej wywołań fork ()), zużywa mniej czasu procesora użytkownika, co daje podobny wynik Czas procesora w porównaniu do mojej wersji powłoki Bourne'a. Próbując skrócić czas pracy procesora przez użytkownika w powłoce Bourne'a, wiem, że większość tego czasu spędza się na konwersjach wielobajtowych.
szczęśliwie
4

Napisałem o tym jednym ze współautorów Basha, a oto jego odpowiedź:

To naprawdę nie jest błąd, ale z pewnością jest to zastrzeżenie.

Chodzi o to, aby zawiesić procesy, które są inną jednostką szczegółowości niż polecenia powłoki. Gdy proces jest zawieszony, wraca do powłoki (ze stanem niezerowym, co ma konsekwencje, gdy, powiedzmy, zatrzymujesz proces, który jest testem pętli), który ma wybór: może przerwać lub kontynuować pętlę , pozostawiając za sobą zatrzymany proces. Bash wybiera - i zawsze tak wybrał - aby wyjść z pętli, gdy zadanie zostanie zatrzymane. Kontynuacja pętli rzadko jest tym, czego chcesz.

Niektóre inne powłoki wykonują takie czynności, jak rozwidlenie kopii powłoki, gdy proces zostaje zawieszony z powodu SIGTSTP i zatrzymanie tego procesu. Bash nigdy tego nie zrobił - wydaje się to bardziej skomplikowane niż gwarancje korzyści - ale jeśli ktoś chce przesłać ten kod jako łatkę, przyjrzałbym się wprowadzeniu zmian.

Więc jeśli ktoś chce przesłać łatkę, użyj adresów e-mail znalezionych na stronach podręcznika man.

naprzód
źródło