60

Есть ли простой способ, позволяющий конкретной команде (завершаемой только через Ctrl-C) автоматически запускаться в течение 5 минут?

Например:

minute-command 5-minutes ping www.google.com

или любая другая команда, которая не завершает себя.

Я хотел бы иметь возможность указать ограничение по времени, а не только 5 минут.

6 ответов6

86

На самом деле это то, что timeout для:

TIMEOUT(1)                          User Commands                         TIMEOUT(1)

NAME
       timeout - run a command with a time limit

SYNOPSIS
       timeout [OPTION] DURATION COMMAND [ARG]...
       timeout [OPTION]

DESCRIPTION
       Start COMMAND, and kill it if still running after DURATION.

lx@lxtp:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
62

Есть (как минимум) две программы, которые предоставляют эту функциональность:

НАЗВАНИЕ

timelimit - эффективно ограничить абсолютное время выполнения процесса

СИНТАКСИС

timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]

а также

НАЗВАНИЕ

timeout - запустить команду с ограничением по времени

СИНТАКСИС

timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]

Они упакованы следующим образом:

$ dlocate `which timeout timelimit`
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout

Сравнение:

/-----------------------------+------------+----------------\
|            Feature          |  timelimit |     timeout    |
+=============================+============+================+
|   time to run               | -t time    | first argument |
+-----------------------------+------------+----------------+
|   terminate signal          | -s signal  | -s signal      |
+-----------------------------+------------+----------------+
|   grace period              | -T time    | -k time        |
+-----------------------------+------------+----------------+
|   kill signal               | -S signal  | (note 1)       |
+-----------------------------+------------+----------------+
|   propagate signals         | -p         | (note 2)       |
\-----------------------------+------------+----------------/

Заметки:

  1. timeout всегда использует SIGKILL качестве последнего сигнала.
  2. timeout не имеет никаких функций для выхода с сигналом, когда это делает дочерняя программа.

Состояние выхода этих двух программ различается, но трудно аккуратно подвести итог, поэтому я советую вам самим обратиться к справочным страницам.

Поскольку timeout установлен по умолчанию на большем количестве систем (во многих дистрибутивах coreutils является стандартным пакетом), я рекомендую использовать его, если вам не нужны дополнительные функции, предоставляемые timelimit .

14

Встроенный Pure bash , без Coreutils

Я обнаружил, что это решение работает в bash опираясь на встроенную команду без вызова внешнего исполняемого файла. Он работает в системе, где в конце концов даже не были установлены coreutils [ 1 ]

YourCommand & read -t 300 ;  kill $!                           # 1st version
YourCommand & read -t 300 || kill $!                           # 2nd version 

Пояснения: как обычно, когда вы отправляете команду в фоновом режиме с & , ее PID сохраняется во внутренней переменной $! (присутствует в современной версии dash , csh , bash , tcsh , zsh ...).
Разница между оболочками действительно заключается в наличии встроенной команды read [ 2 ] и опции -t . В 1-й версии, если пользователь не завершит строку ввода до указанного количества секунд, инструкция будет прервана и будет сгенерирован код возврата ошибки.

-t TIMEOUT Вызывает чтение до истечения времени ожидания и возвращает ошибку, если полная строка ввода не считывается в течение TIMEOUT секунд.

Вторая версия работает как первая, но вы можете прервать тайм-аут, просто нажав Enter.
Действительно оператор или || выполняет оператор kill только в том случае, если команда read завершается с кодом возврата, отличным от нуля, как по истечении времени ожидания. Если вы нажмете ввод до этого момента, он вернет 0 и не убьет вашу предыдущую команду.


Решения Coreutils [ 1 ]

Если в вашей системе присутствуют coreutils , и вам не нужно экономить время и ресурсы для вызова внешней программы, timeout и sleep - это идеальный способ достичь своей цели.

timeout Использование timeout просто.
В конце концов, вы можете использовать опцию -k для отправки дополнительного сигнала уничтожения, если первый сбой.

timeout 5m YourCommand                                         # 3rd version 

sleep Со sleep вы можете использовать свою фантазию или вдохновение [ 3 ]. Обратите внимание, что вы можете оставить свою команду в фоновом режиме или на переднем плане (например, top обычно должен быть на переднем плане).

YourCommand & sleep 5m; kill $!                                # 4th Background
YourCommand & pid=$! ; (sleep 5m; kill $pid;) &                # 5th Background

bash -c '(sleep 5m; kill $$) & exec YourCommand'               # 6th Foreground
(cmdpid=$BASHPID; (sleep 5m; kill $cmdpid) & exec YourCommand) # 7th Foreground

Пояснения

  • В 4-й версии вы выполняете в фоновом режиме YourCommand затем ваша оболочка sleep течение 5 минут. Когда будет закончен последний фоновый процесс ($!) будет убит. Вы останавливаете свою раковину.
  • В 5-й версии вместо этого вы выполняете в фоновом режиме YourCommand и немедленно сохраняете этот PID в переменной $pid . Затем вы выполняете в фоновом режиме дремоту 5 минут и последующую команду, которая уничтожит этот сохраненный PID. Так как вы отправили эту группу команд в фоновом режиме, вы не остановите свою оболочку. Вам нужно хранить PID в переменной, потому что значение $! может быть обновлено путем возможного выполнения другой программы в фоновом режиме. Проще говоря, вы избегаете риска убить неправильный процесс или вообще ни одного процесса.
  • В 6-й версии это называется новой оболочкой bash, которая самоубийство самоубийства через 5 минут через $$, затем выполняется ваша команда, которая остается на переднем плане.
  • В 7-й версии он вызывается subshell () который сохраняет свой PID в переменной (cmdpid) и убивает себя с помощью другого subshell, отправленного в фоновом режиме, а затем запускает YourCommand на переднем плане.

Конечно, в каждой версии вы можете посылать необходимый сигнал уничтожения, от стандартного до экстремального kill -9 , который будет использоваться только тогда, когда это действительно необходимо.

Рекомендации

  • [ 1 ] Coreutils
  • [ 2 ] Руководство для начинающих Bash
  • [ 3 ] BASFAQ
10

В вашем конкретном случае большинство реализаций ping поддерживают -c или --count для завершения после определенного количества пингов:

ping -c 300 host.example.com

Для более общего решения см. Другие ответы.

8

Вы можете сделать это с помощью простого скрипта:

#!/bin/bash

#
# $1 is the time to let the program run, and $2, $3, ... are the command itself.
#

"${@:2}" &
PID=$!
sleep "${@:1:1}"
kill -2 $PID

(сигнал SIGINT = 2 используется в соответствии с предложением Матии Налис в комментарии ниже).

Объяснение (редкость?) Выражение bash $@:...: позиционные параметры, ($*, $@, "$*", "$@") допускают следующую дополнительную спецификацию, например:

"${@:START:COUNT}"

что означает: из всех параметров возьмите COUNT из них, первый из которых будет выбран в положении START; если COUNT опущен, возьмите их все до конца, начиная с позиции STARTth. Помните, что $0 - это имя программы. Если START отрицателен, начните отсчет с конца и помните, что COUNT не может быть отрицательным, поэтому последний аргумент - "${@:-1}" . Кроме того, почти всегда включайте позиционные параметры в двойные кавычки.

4

Поскольку вы упоминаете ping в вашем примере; у этой команды есть несколько вариантов остановки через определенное время:

  • w deadline Укажите время ожидания в секундах, прежде чем ping завершится независимо от того, сколько пакетов было отправлено или получено. В этом случае ping не останавливается после отправки пакета подсчета , он ожидает либо истечения крайнего срока, либо ответа на зондов подсчета , либо сообщения об ошибке из сети.
  • W timeout Время ожидания ответа в секундах. Опция влияет только на тайм-аут при отсутствии каких-либо ответов, в противном случае ping ожидает двух RTT.

- man ping

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .