POSIX еквівалент таймауту GNU?


14

Команда GNU coreutils timeoutнадзвичайно зручна для певних сценаріальних ситуацій, дозволяє використовувати вихід команди, якщо вона швидко запускається, і пропускати її, якщо це займе занадто довго.

Як я можу наблизити основну поведінку timeoutвикористання лише визначених POSIX утиліт?


(Я маю в виду , що може включати в себе комбінацію wait, sleep, killі хто знає , що ще, але , можливо , я НЕ вистачає більш легкий підхід.)


3
Див. Час вичерпання в сценарії оболонки , але я не вважаю це дублікатом, оскільки я вимагав переносимості до систем POS-POSIX, і у мене була вимога збереження stdin та stdout, які деякі рішення, що включають фонові процеси, виключають.
Жил "ТАК - перестань бути злим"

command & pid=$! ; sleep 5 && kill $pid
Пандія

1
@Pandya чи не вводить такий стан легкої гонки, коли, якщо commandшвидко закінчується, є невелика ймовірність pidповторного використання іншого процесу до запуску killкоманди? Я б не хотів, щоб це у виробничому коді ....
Wildcard

Чи можете ви пояснити більше основної проблеми, яку ви намагаєтеся вирішити? Чому б просто не скласти timeoutпрограму і не використовувати її?
Джеймс Янгмен

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

Відповіді:


2

Мій підхід був би таким:

  • Виконати команду як фоновий процес 1

  • Виконайте "сторожовий таймер" як фоновий процес 2

  • Налаштуйте обробник, щоб захопити сигнал завершення в батьківській оболонці

  • Зачекайте завершення обох процесів. Процес, який закінчується спочатку, надсилає сигнал закінчення батькові.

  • Батьківський обробник пастки вбиває обидва фонові процеси за допомогою контролю за роботою (один з них вже припинено за визначенням, але це вбивство буде нешкідливим неоператором, оскільки ми не використовуємо PID, див. Нижче)

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

#!/bin/sh

TIMEOUT=$1
COMMAND='sleep 5'

function cleanup {
    echo "SIGTERM trap"
    kill %1 %2
}

trap cleanup SIGTERM

($COMMAND; echo "Command completed"; kill $$) &
(sleep $TIMEOUT; echo "Timeout expired"; kill $$) &

wait
echo "End of execution"

Результат для TIMEOUT=10(команда припиняється перед сторожовою собакою):

$ ./timeout.sh 10
Command completed
SIGTERM trap
End of execution

Результат для TIMEOUT=1(сторожовий пес закінчується перед командою):

$ ./timeout.sh 1
Timeout expired
SIGTERM trap
End of execution

Результат для TIMEOUT=5(сторожовий пес і команда закінчуються "майже" одночасно):

./tst.sh 5
Timeout expired
Command completed
SIGTERM trap
End of execution

Це не сумісно з POSIX, оскільки (а) має бути визначення функції cleanup() { ...; }та (b) контроль роботи - це функція bash, не визначена POSIX (хоча ksh та інші також мають). Хороший сценарій, хоча!
Wildcard

Ви можете також зробити краще timeout="$1"; shiftі (exec "$@"; echo "Command completed"; kill $$)краще , ніж повторно wordsplitting список аргументів.
Wildcard
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.