Какой простой способ запустить команду на 5 минут? [Дубликат]

66

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

Например:

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

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

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

Экхарт
источник

Ответы:

67

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

ИМЯ

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.

Тоби Спейт
источник
10
Почему вы используете один, а не другой?
Брайс М. Демпси
2
@ BriceM.Dempsey На моем локальном компьютере тайм-аут присутствует, но ограничения по времени нет (хотя он доступен в репо). Итак, если один из них предустановлен ... Кроме этого, просто глядя на сигнатуры методов, я вижу, что они делают разные вещи и имеют разные варианты использования.
Benubird
Обратите внимание, что существует как минимум две реализации timelimit. Смотрите Как я могу завершить процесс и быть уверенным, что PID не был повторно использован для получения дополнительной информации о них и времени ожидания GNU.
СЧ
1
@ BriceM.Dempsey timeoutвключен в GNU coreutils , timelimitно не включен . Вы можете установить ни один, один или оба. Для второго сообщается, что ограничение по времени выполняет команду и завершает порожденный процесс через заданное время с данным сигналом. Сначала отправляется сигнал «предупреждение» , затем, после тайм-аута, сигнал «убить», аналогично тому, как init (8) работает при выключении. Так что даже в середине другое поведение.
Хастур
Поскольку GNU coreutils предустанавливается на каждом GNU / Linux, timeoutэто путь туда.
rexkogitans
87

На самом деле, это то, что 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
Гомбай Шандор
источник
16

Чистый 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.
Действительно, оператор or ||выполняет killоператор только в том случае, если readкоманда завершается с кодом возврата, отличным от нуля, как по истечении времени ожидания. Если вы нажмете enterдо этого момента, он вернет 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-й версии он вызывает подоболочку, ()которая сохраняет свой PID в переменной ( cmdpid) и убивает себя другой подоболочкой, отправляемой в фоновом режиме, а затем запускает YourCommand на переднем плане.

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

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

  • [ 1 ] Coreutils
  • [ 2 ] Руководство для начинающих Bash
  • [ 3 ] BASFAQ
Hastur
источник
2
«Со сном вы можете использовать свою фантазию или вдохновиться [ссылка на Bash FAQ]» +1 #thatoughoughinternetfortoday
joeytwiddle
11

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

ping -c 300 host.example.com

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

Тоби Спейт
источник
7
У меня сложилось впечатление, что ОП только что предоставил pingконкретный пример. Он не хочет индивидуального решения для каждой отдельной программы.
user1717828 25.02.16
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 из них, первым из которых будет значение, которое находится в положении STARTth; если COUNT опущен, возьмите их все до конца, начиная с позиции STARTth. Помните, что $0это имя программы. Если START отрицателен, начните отсчет с конца и помните, что COUNT не может быть отрицательным, поэтому последний аргумент - это "${@:-1}". Кроме того, почти всегда включайте позиционные параметры в двойные кавычки.

MariusMatutiae
источник
1
Вероятно, я бы разработал сценарий так, чтобы он принимал время в качестве первого или последнего аргумента и выполнял все остальные аргументы в качестве команды. Позволить bash разделить слова $1довольно грубо. Кроме того, вы можете просто sleep "$1"или что-то в countdown.
Питер Кордес
1
@PeterCordes Готово, согласно вашим пожеланиям.
MariusMatutiae
Время в первом аргументе позволяет вам это сделать time=$1; shift, а затем вам не нужен синтаксис разбиения массива для позиционных параметров. Но да, это намного проще.
Питер Кордес
1
@PeterCordes Согласен, но вы спросили меня, знаю ли я, как безопаснее это сделать, и просто ленивый, или просто невежественный. лол.
MariusMatutiae
поскольку автор специально спросил о программе, которую можно прервать ctrl-c, лучше попробовать kill -INTвместо kill -9(или, по крайней мере, попытаться -9только через несколько секунд, если первая не удалась - это дает программе возможность чисто завершиться и не оставлять временные файлы). и т.д. вокруг)
Матия Налис
5

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

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

-man ping

user2428118
источник