Выполнить команду по истечении определенного промежутка времени?

24

Если я выполняю долгий процесс, могу ли я выполнить какие-то временные команды?

Например, я выполняю очень длинный процесс, который длится примерно 10 минут.

Через 5 минут я бы хотел запустить отдельную команду. Для иллюстрации, отдельная команда может быть:echo 5 minutes complete

(Примечание: я не хочу продвигаться к завершению команды, а просто к командам, выполняемым через указанные интервалы.)

Является ли это возможным?

Аникет Бхаттачарья
источник
1
В большинстве случаев вы не знаете заранее, сколько времени займет процесс.
Чороба
Что вы имеете в виду под «командами на основе времени»? Вы хотите создать индикатор выполнения? Основываясь на текущей формулировке вашего вопроса, вы можете просто поместить длительную команду в фоновом режиме и затем отобразить системные часы. Просьба уточнить.
Wildcard
@Wildcard Я уточнил в вопросе. Не прогрессбар. Он будет выполнять команды через определенные промежутки времени
Аникет Бхаттачарья
1
«5 минут завершено» - странная вещь для эха. Не "прошло 5 минут"? Не "Время _____"? Вы просто хотите убедиться, что какой-то определенный интервал времени истек с момента запуска вашей длительной команды до запуска другой произвольной команды? Если так, то почему бы просто не бежать longcommand & sleep 300 && command-to-do-after-five-minutes? (На самом деле это, вероятно, то, что вы ищете.) Обратите внимание, что вашего разъяснения было недостаточно, так как вы сразу получили две реализации тактового индикатора выполнения.
Wildcard

Ответы:

29

Просто беги:

long-command & sleep 300; do-this-after-five-minutes

do-this-after-five-minutesПолучит бежать через пять минут. long-commandБудет работать в фоновом режиме.

Wildcard
источник
10
Я обычно использую sleep 5m && foobar, поэтому, если я передумаю и ^ C the sleep, следующая команда не запустится.
Питер Кордес
@PeterCordes, когда я тестировал его, например, sleep 3; lsи ^C, вторая команда все равно не запускалась. Не совсем уверен, почему и, возможно, он работает по-другому в неинтерактивной оболочке?
Wildcard
1
@PeterCordes Не совсем - если только это не отличается для каждой оболочки. Когда sleep 5m && echoспит, когда вы приостанавливаете, приостанавливается только sleepкоманда. Остальная часть командной строки выполняется, но, поскольку она sleepбыла приостановлена, она не завершилась успешно, а часть после &&пропускается. Попробуйте приостановить sleep 5 || echo hello, и helloпоявляется сразу после нажатия ^Z.
августа
1
@hvd: Да, вы правы, и я снова ошибаюсь>. <, используя bash4. По-видимому, прошло слишком много времени с тех пор, как я решил, что && был подходом для гетто at(1), для таких вещей, как sleep 30m && mplayer something.mp3напоминание о тревоге или для sleep 90m && fgвозобновления команды, интенсивно использующей диск. Так что на самом деле, sleep 5m && echo helloэто хорошо, потому что ^Zприостанавливается sleepбез выполнения следующей команды. Если вы хотите иметь возможность приостановить / возобновить всю составную команду, даже до выхода из спящего режима, используйте ( sleep 2 && echo hello ).
Питер Кордес
@hvd: &&Идиома позволяет вам быть абсолютно уверенным, что вы не убьете процесс сразу после^Z запуска сна (потому что вы можете не запускать команду, а не рисковать ^C). Это полезно в случае использования sleep && fgили в sleep && bgслучае, когда возобновляемая команда частично проходит через что-то медленное.
Питер Кордес
5

Вы можете использовать этот скрипт:

#!/bin/bash

TEMPFILE="$(mktemp)"
STARTTIME="$(date +%s)"
(./longprocess; rm -f "$TEMPFILE") &
while [ -f "$TEMPFILE" ]; do
    sleep 1s
    NOW="$(date +%s)"
    if (( (NOW-STARTTIME) % 300 == 0 )); then
        echo "$(( (NOW-STARTTIME)/60 )) minute(s) elapsed"
    fi
done
echo "Done!!!"

Он выполняет ваши действия longprocessв, sub-shellа затем отслеживает ранее созданный файл блокировки на существование.

саржа
источник
2
Проверьте man bashдля SECONDS. Вы можете установить SECONDS=0при запуске скрипта и только проверять на большее или равное 300 или устанавливать SECONDS=$((date +%s))и забыть dateснова использовать в вашем скрипте ...
@yeti, спасибо за подсказку, я этого не знал.
Серж
@yeti, если вы хотите полагаться на время после того, чтобы sleep 1sвсегда быть ровно на одну секунду позже, чем было раньше sleep 1s... тогда вы стали жертвой Ложей, в которые программисты верят во времени . (Хотя в этом случае вы могли бы просто показать индикатор выполнения хеш-метки или что-то в этом роде.)
Wildcard
@Wildcard ... я вообще не упоминал sleep!
@yeti, верно. Спасибо за отзыв о SECONDS! :)
Wildcard
4

Для этого есть один вкладыш:

( ( sleep $TIMEOUT ; echo "5 minutes complete") & $COMMAND )

В вашем случае TIMEOUT = 5 м, а COMMAND - длинная команда.

Также см. Мой ответ на это сообщение Тайм-аут с «перезагрузка сети службы»

coffeMug
источник
Запуск подоболочки на переднем плане, а затем выполнение команды кажется излишне сложным. Я бы убрал внешние скобки и exec.
Гленн Джекман
1
@glennjackman Таким образом, можно убить всю процедуру, отправив CTRL + C (например) в основную (внешнюю) суб-оболочку.
coffeMug
1
Но, используя exec, у вас больше нет подоболочки, у вас просто есть команда. Родителем команды является оболочка, выполняющая скрипт, как если бы вы не использовали подоболочку вообще.
Гленн Джекман
3
#! /bin/bash

( sleep 4 ) & # <-- The long running process.

seconds=1
while jobs %1 &>/dev/null ; do
    echo $((seconds++)) seconds complete
    sleep 1    
done
echo Done.

jobs %1 не удается после завершения задания% 1.

Обратите внимание, что в течение более длительного времени $ секунд может не синхронизироваться с реальным временем. Лучше сохранить время начала и вычислить разницу с фактическим временем.

choroba
источник