Чому цикл на час зупиняється після призупинення?


10

Чому так, що використовуючи bash та призупиняючи цикл, а цикл припиняється після відновлення? Короткий приклад нижче.

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

Мені знайомі сигнали, і я здогадуюсь, що це може бути природна поведінка баша тут, але я хотів би краще зрозуміти, чому він поводиться саме таким чином.


тому що він повинен впоратися з перериванням і повинен точно відображати це у $?відповідь, і так trueне є true. мабуть. я думаю.
mikeserv

1
Я сподіваюся, що цей коментар не потрапить до позначення, але я відповім на ваше запитання ще одним питанням у стилі Unix koan: "Чому студент припиняє битися на ігровому майданчику після того, як його призупиняють?" Відповідь - тому, що він більше не знаходиться на майданчику, де він має можливість розпочати бої. Таким чином, поведінка, про яку йдеться, просто була зупинена.
rubynorails

Ви зупиняєте команду, цикл розбивається. Тоді ви відновите команду одиночного сну 1, а не цикл.
123

Відповіді:


10

Це схоже на помилку в декількох оболонках, працює як очікується з ksh93 та zsh .

Фон:

Більшість оболонок, здається, виконують цикл while всередині основної оболонки та

Борн Шелл призупиняє всю оболонку, якщо ви введете ^ Z з оболонкою без входу

bash призупиняє тільки, sleepа потім залишає цикл while на користь друку нового підказки оболонки

dash робить цю команду непридатною

З ksh93 справи працюють дуже інакше:

ksh93 робить те саме, тоді як команда запускається вперше, але як sleepі бутін у ksh93, ksh93 має обробник, який викликає цикл while відщеплення від основної оболонки, а потім призупинення в момент введення ^ Z.

Якщо пізніше ви введете ksh93fg , роздвоєна дитина, яка все ще працює циклом, продовжується.

Ви бачите основну відмінність, порівнюючи повідомлення контрольного завдання з bash та ksh93:

bash звіти:

[1]+ Stopped sleep 1

але ksh93 повідомляє:

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

zsh поводиться схоже на ksh93

З обома оболонками у вас є один процес (основна оболонка), якщо ви не введете ^ Z, і два процеси оболонки після введення ^ Z.


насправді не dashзакінчується обробкою сигналу, коли цикл закінчується? у [d]?ashвихідному коді є всі ці макроси для INTON та INTOFF, розповсюджені по всьому, і зазвичай сигнали, отримані в стані INTOFF, справді обробляються в (або навколо) INTON . у будь-якому випадку, я лише цікавий, чому я думаю, ви знаєте краще - це чудова відповідь. Дякую тобі.
mikeserv

Я дуже рідко використовую тире, і я нещодавно добирав і компілював його для порівняння продуктивності з bash, ksh93 та моїм Bourne Shell. Роблячи ці тести, я виявив, що тире в основному здається швидким, оскільки не включає підтримку багатобайтових символів. Синглу sleep 100можна призупинити та відновити dash, тому, здається, він dashзнає про проблеми в цій команді та вибірково відключає контроль за роботою.
schily

значить, у ваших тестах ви змогли зрівняти dashефективність роботи в інших оболонках, скинувши багатобайтову обробку? і так, dashпідтримує контроль за роботою, але стандарт говорить, що інтерактивна оболонка повинна ігнорувати TSTP, а цикл, який працює в поточній оболонці на інтерактивному терміналі, є не менш інтерактивною оболонкою, ніж будь-який інший.
mikeserv

Я не перевіряв цього точно, але міг бачити, що, хоча тире споживає більше системного часу процесора, ніж ksh93 або Bourne Shell (головним чином тому, що він видає більше викликів fork ()), він використовує менше часу для процесора користувача, і це призводить до схожої загальної кількості Час процесора порівняно з моєю версією Bourne Shell. З спроб скоротити час роботи процесора в оболонці Bourne, я знаю, що більшість цього часу витрачається на багатобайтові перетворення.
schily

4

Я написав одного з співавторів Bash про це питання, і ось його відповідь:

Це насправді не помилка, але це, безумовно, застереження.

Ідея тут полягає в тому, що ви призупиняєте процеси, які є іншою одиницею деталізації, ніж команди оболонки. Коли процес призупинено, він повертається до оболонки (з ненульовим статусом, що має наслідки, коли ви, скажімо, зупиняєте процес, який є тестом циклу), у якого є вибір: він може вирватися з або продовжити цикл , залишивши зупинений процес позаду. Bash вибирає - і завжди обирав - вириватися з циклів, коли робота припиняється. Продовжуючи цикл рідко, що ви хочете.

Деякі інші оболонки роблять такі речі, як розщеплення копії оболонки, коли процес призупиняється через SIGTSTP, і зупиняють цей процес. Баш ніколи цього не робив - це здається складнішим, ніж гарантує вигода, - але якщо хтось хоче подати цей код як патч, я б поглянув на внесення змін.

Тож якщо хтось хоче надіслати виправлення, використовуйте електронні адреси, знайдені на сторінках man.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.