Запустити команду через певний проміжок часу?


24

Якщо я виконую тривалий процес, чи є якийсь спосіб виконати деякі команди, засновані на часі?

Наприклад, я запускаю дійсно довгий процес, який триває приблизно 10 хвилин.

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

(Примітка. Я не хочу просуватися до завершення команди, а просто команди, виконані через задані інтервали.)

Це можливо?


1
У більшості випадків ви не знаєте заздалегідь, скільки триватиме процес.
choroba

Що ви маєте на увазі "команди, засновані на часі"? Ви хочете створити панель прогресу? Виходячи з поточного фразування вашого питання, ви можете просто поставити довгу команду, що працює, на задньому плані, а потім відобразити системний годинник. Поясніть будь ласка.
Wildcard

@Wildcard Я уточнив у питанні. Не панель прогресу. Він виконує команди через певні інтервали
Aniket Bhattacharyea

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Буде працювати у фоновому режимі.


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.
hvd

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не запускати команду, а не ризикувати a ^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м, і КОМАНД - це довга команда.

Також дивіться мою відповідь на цю публікацію Timeout з "перезавантаженням сервісної мережі"


Запуск підпалу на передньому плані, а потім виконання команди здається непотрібним. Я б видалив зовнішні дужки та exec.
glenn jackman

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.

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

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