Uruchomić polecenie po upływie określonego czasu?


24

Jeśli wykonuję długi proces, czy jest jakiś sposób na wykonanie niektórych poleceń opartych na czasie?

Na przykład uruchamiam naprawdę długi proces, który trwa około 10 minut.

Po 5 minutach chciałbym uruchomić osobne polecenie. Na przykład osobnym poleceniem może być:echo 5 minutes complete

(Uwaga: nie chcę postępu w realizacji polecenia, ale po prostu polecenia wykonywane po określonych odstępach czasu).

Czy to możliwe?


1
W większości przypadków nie wiesz z góry, jak długo potrwa proces.
choroba

Co masz na myśli „polecenia oparte na czasie”? Czy chcesz utworzyć pasek postępu? Na podstawie bieżącego sformułowania pytania możesz po prostu umieścić długo działające polecenie w tle, a następnie wyświetlić zegar systemowy. Proszę o wyjaśnienie.
Wildcard

@Wildcard Wyjaśniłem w pytaniu. Nie pasek postępu. Będzie wykonywać polecenia po pewnym czasie
Aniket Bhattacharyea

1
„Ukończono 5 minut” to dziwne echo. Nie „upłynęło 5 minut”? Nie „Czas jest _____”? Czy chcesz po prostu upewnić się, że upłynął określony przedział czasu od momentu uruchomienia długo działającego polecenia, przed uruchomieniem innego dowolnego polecenia? Jeśli tak, dlaczego po prostu nie uruchomić longcommand & sleep 300 && command-to-do-after-five-minutes? (Właściwie to prawdopodobnie tego szukasz). Zauważ, że twoje wyjaśnienie nie było wystarczające, ponieważ od razu otrzymałeś dwie implementacje paska postępu zegara.
Wildcard

Odpowiedzi:


29

Po prostu biegnij:

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

Uruchomi do-this-after-five-minutessię po pięciu minutach. long-commandZostanie uruchomiony w tle.


10
Zwykle używam sleep 5m && foobar, więc jeśli zmienię zdanie i ^ C sleep, następne polecenie nie zostanie uruchomione.
Peter Cordes

@PeterCordes, kiedy testowałem to np. sleep 3; lsI ^C, drugie polecenie i tak nie działa. Nie bardzo wiem, dlaczego i może działa inaczej w nieinteraktywnej powłoce?
Wildcard

1
@PeterCordes Niezupełnie - chyba że różni się w zależności od powłoki. Kiedy sleep 5m && echośpi, kiedy się zawieszasz, tylko sleeppolecenie jest zawieszone. Reszta wiersza poleceń jest uruchomiona, ale ponieważ sleepzostała zawieszona, nie zakończyła się pomyślnie, a część po nim &&została pominięta. Spróbuj zawiesić sleep 5 || echo helloi hellopokazuje się bezpośrednio po naciśnięciu ^Z.
hvd

1
@hvd: Tak, masz rację i znów się mylę>. <, używając bash4. Najwyraźniej minęło dużo czasu, odkąd zdecydowałem, że && to droga do getta at(1), do takich rzeczy jak sleep 30m && mplayer something.mp3przypomnienie o alarmie lub sleep 90m && fgdo wznowienia polecenia wymagającego dużej ilości dysku. Tak naprawdę sleep 5m && echo hellojest fajne, ponieważ ^Zzawiesza się sleepbez uruchamiania następującego polecenia. Jeśli chcesz móc zawiesić / wznowić całą komendę złożoną, nawet przed wyjściem z trybu uśpienia, użyj ( sleep 2 && echo hello ).
Peter Cordes

@hvd: Ten &&idiom pozwala być absolutnie pewnym, że nie zabijesz procesu zaraz po uruchomieniu trybu uśpienia (ponieważ nie możesz ^Zuruchomić polecenia, zamiast ryzykować a ^C). Jest to przydatne w przypadku sleep && fglub w sleep && bgprzypadku użycia, gdy wznawiane polecenie jest częściowo realizowane przez coś powolnego.
Peter Cordes

5

Możesz użyć tego skryptu:

#!/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!!!"

Wykonuje twój longprocessw, sub-shella następnie monitoruje wcześniej utworzony plik blokady.


2
Sprawdzić man bashza SECONDS. Możesz ustawić SECONDS=0na początku skryptu i tylko sprawdzić, czy jest większy lub równy 300, lub ustawić SECONDS=$((date +%s))i zapomnieć o dateponownym użyciu w skrypcie ...

@yeti, dzięki za podpowiedź, nie wiedziałem o tym.
Serge

@yeti, jeśli chcesz polegać na czasie po sleep 1sbyciu dokładnie o jedną sekundę później niż wcześniej sleep 1s... to padłeś ofiarą Falsehoods, które programiści wierzą w czas . (Chociaż w tym przypadku równie dobrze możesz po prostu pokazać pasek postępu znaku skrótu lub coś takiego.)
Wildcard

@Wildcard ... W ogóle nie wspomniałem sleep!

@yeti, masz rację. Dzięki za podpowiedź SECONDS! :)
Wildcard

4

Jest do tego jedna linijka:

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

W twoim przypadku TIMEOUT = 5m, a POLECENIE jest długim poleceniem.

Zobacz także moją odpowiedź na ten post Limit czasu z „restartem sieci serwisowej”


Uruchomienie podpowłoki na pierwszym planie, a następnie wykonanie polecenia wydaje się niepotrzebnie skomplikowane. Chciałbym usunąć zewnętrzne nawiasy i exec.
glenn jackman

1
@glennjackman W ten sposób można zabić całą procedurę, wysyłając CTRL + C (na przykład) do głównej (najbardziej zewnętrznej) podpowłoki.
coffeMug

1
Ale używając exec, nie masz już podpowłoki, po prostu masz polecenie. Rodzic polecenia jest powłoką uruchamiającą skrypt, tak jakby w ogóle nie była używana podpowłoka.
glenn jackman

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 kończy się niepowodzeniem po zatrzymaniu zadania% 1.

Pamiętaj, że w dłuższych czasach $ sekundy mogą nie być zsynchronizowane z czasem rzeczywistym. Lepiej zapisać czas rozpoczęcia i obliczyć różnicę do czasu rzeczywistego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.