Czy powtarzać polecenie co x odstęp czasu w terminalu?


142

Jak mogę powtarzać polecenie w każdym przedziale czasu, aby umożliwić mi uruchamianie poleceń w celu sprawdzenia lub monitorowania katalogów?

Skrypt nie jest potrzebny, potrzebuję tylko prostej komendy do wykonania w terminalu.

Odpowiedzi:


219

Możesz użyć watchpolecenia, zegarek służy do uruchamiania dowolnego wyznaczonego polecenia w regularnych odstępach czasu.

Otwórz terminal i wpisz:

watch -n x <your command>

zmień x na żądany czas w sekundach.

Aby uzyskać dodatkową pomoc w korzystaniu z watchpolecenia i jego opcji, uruchom man watchlub odwiedź ten link .

Na przykład: co 60. na tym samym terminalu będzie wyświetlana zawartość katalogu Desktop, aby można było wiedzieć, czy nastąpiły jakieś zmiany:

watch -n 60 ls -l ~/Desktop

34
+1, ale zachowaj ostrożność podczas korzystania z rozszerzeń. Na przykład wypróbuj różnicę pomiędzy watch -n 1 'echo $COLUMNS'i watch -n 1 echo $COLUMNSpodczas zmiany rozmiaru terminala - ten pierwszy jest rozwijany co sekundę, ale drugi jest rozszerzany tylko raz przed uruchomieniem watch.
— l0b0

To działa jak urok ! Ty nux

Problem z tym rozwiązaniem polega na tym, że nie można uruchamiać oglądania jako procesu i po prostu pozostawić go uruchomionego w tle (na przykład z & disown)
— Cestarian

2
Czy jest jakiś sposób na użycie watchpolecenia typu „włączona historia”? Uwielbiam używać watch, ale czasami wolałbym zobaczyć dziennik poprzednich wykonań, zamiast tylko ostatniego. I tak, wiem, że mogę to zrobić za pomocą skryptów ( while true), ale korzystanie z watchnarzędzia jest o wiele czystsze!
— rinogo

działało to dla prostszych poleceń, ale w przypadku łańcuchowych poleceń potokowych nie działało to dla mnie .. następna była komenda, której próbowałem => cat api.log | grep „woła” | wc -l
— Sudip Bhandari

90

Możesz także użyć tego polecenia w terminalu, oprócz odpowiedzi nux:

while true; do <your_command>; sleep <interval_in_seconds>; done

Przykład

while true; do ls; sleep 2; done

To polecenie wydrukuje wydruk lsw odstępie 2 sekund.

Użyj Ctrl+, Caby zatrzymać proces.

Istnieje kilka wad watch

  • Nie można używać żadnych aliasowanych poleceń.
  • Jeśli dane wyjściowe dowolnego polecenia są dość długie, przewijanie nie działa poprawnie.
  • Występują problemy z ustawieniem maksymalnego odstępu czasu powyżej określonej wartości.
  • watchzinterpretuje sekwencje kolorów ANSI przekazując znaki zmiany znaczenia za pomocą -club --color. Na przykład wyjście pygmentizebędzie działać, ale nie powiedzie się ls --color=auto.

W powyższych okolicznościach może się to wydawać lepszą opcją.


watchistnieje dla tego, to jest trochę bezużyteczne powiedziałbym
— Bruno Pereira

14
Nie twierdzę, że tej odpowiedzi należy użyć na pierwszym miejscu. watchjest dobry w większości przypadków. Dlatego na początku wspomniałem „oprócz odpowiedzi Nux”. Ale z kilkoma problemami jest watchna przykład Nie można używać żadnych aliasowanych poleceńwatch . Weźmy na przykład llalias, ls -laFale nie można go używać z watch. Również w przypadku, gdy wyjście dowolnego polecenia jest dość długie, będziesz mieć problemy z przewijaniem za pomocą watch. W tych kilku szczególnych przypadkach odpowiedź ta może wydawać się lepszą opcją.
— souravc

@souravc Moja wersja watchco najmniej zezwala na opcje -club --colordla kolorowych wyników.
— Lily Chung,

8
while sleep xjest lepszy - łatwiej zabijać.
— d33tah

3
Jest to miła alternatywa i, w przeciwieństwie do watch, pozwala zachować historię poleceń.
— adelriosantiago

34

Chciałem tylko dodać odpowiedzi do souravc i nux :

  1. Chociaż watchbędzie działał idealnie na Ubuntu, możesz tego uniknąć, jeśli chcesz, aby Twój „Unix-fu” był czysty - na przykład na FreeBSD, watch to polecenie „szpiegować na innej linii tty”.
  2. while true; do command; sleep SECONDS; doneposiada również zastrzeżenie - to polecenie może być trudniejsze do zabicia za pomocą CTR + C . Może wolisz while sleep SECONDS; do command; done- jest nie tylko krótszy, ale także łatwiejszy do przerwania. Zastrzeżenie polega na tym, że najpierw będzie spało, a następnie uruchomi polecenie, więc musisz poczekać, SECONDSzanim nastąpi pierwsze wystąpienie polecenia.

2
Mam nadzieję, że jest to akceptowalne jako odpowiedź zamiast komentarza - chciałem tu pokazać inne rozwiązanie, a komentowanie w rzeczywistości zwróciłoby na mnie mniej uwagi.
— d33tah

Dlaczego dokładnie ma to znaczenie, w którym sleepmiejscu znajduje się whilepętla? Nie mogłem znaleźć żadnej różnicy, Ctrl + C natychmiast przerwał pętlę, bez względu na wszystko.
— deser

@ deser: chyba zależy od tego, co próbujesz się wyrwać. Normalnie, ctrl + c po prostu zabije twoje commandi sleepzłamie tylko jeśli zabijesz true.
— d33tah

11

Brzmi jak idealne zadanie dla crondemona, które pozwala na uruchamianie okresowych poleceń. Uruchom crontab -epolecenie, aby rozpocząć edycję konfiguracji crona użytkownika. Jego format jest udokumentowany w crontab (5) . Zasadniczo masz pięć powiązanych z czasem, oddzielonych spacjami pól, po których następuje polecenie:

The time and date fields are:

       field          allowed values
       -----          --------------
       minute         0-59
       hour           0-23
       day of month   1-31
       month          1-12 (or names, see below)
       day of week    0-7 (0 or 7 is Sunday, or use names)

Na przykład, jeśli chcesz uruchamiać skrypt w języku Python w każdy wtorek, o 11:00:

0 11 * * 1 python ~/yourscript.py

Istnieją również specjalne nazwy, które zastępują czas, np @reboot. Bardzo pomocne, jeśli chcesz utworzyć katalog tymczasowy. Z mojego crontab (wymienionego z crontab -l):

# Creates a temporary directory for ~/.distcc at boot
@reboot ln -sfn "$(mktemp -d "/tmp/distcc.XXXXXXXX")" "$HOME/.distcc"

4
Pytanie dotyczy tego, jak co jakiś czas uruchamiać coś w terminalu. cronbiegnie za kulisami, a nie w terminalu
— północny bradley,

5

Jeśli monitorujesz system plików, to inotifywaitjest genialny i z pewnością powoduje mniejsze obciążenie systemu.

Przykład:

W 1. terminalu wpisz to polecenie:

$ inotifywait .

Następnie w drugim terminalu dowolne polecenie, które wpływa na bieżący katalog,

$ touch newfile

Następnie w oryginalnym terminalu inotifywait obudzi się i zgłosi zdarzenie

./ CREATE newfile2

Lub w pętli

$ while true ; do inotifywait . ; done
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ DELETE newfile
Setting up watches.  
Watches established.
./ CREATE,ISDIR newdir
Setting up watches.  
Watches established.

użytkownik powiedział ci, że nie ma skryptu, a może nie chce niczego monitorować
— oprócz

3
Nie powiedziałem mu, żeby napisał skrypt, zasugerowałem, że jeśli zapętlają się w celu obserwowania określonego zdarzenia w systemie plików, to inotifywait jest użyteczny i zużywa mniej zasobów niż powtarzanie polecenia. Często uruchamiam kilka poleceń w wierszu poleceń, np. Czy grep something InALogFile|lessto skrypt?
— X Tian

to dobra odpowiedź, spróbuj go edytować, aby wyglądać prostiej.
— nux

3
Co może być prostsze niż .nie mogę pominąć polecenia.
— X Tian

Dzięki @XTian, ​​świetne polecenie. Widziałem też teraz na stronie podręcznika, które można dodawać, -maby stale monitorować bez pętli.
— yoniLavi

4

Możesz utworzyć własne repeatpolecenie, wykonując następujące kroki; kredyty tutaj :

Najpierw otwórz .bash_aliasesplik:

$ xdg-open ~/.bash-aliases

Po drugie, wklej te linie na dole pliku i zapisz:

repeat() {
n=$1
shift
while [ $(( n -= 1 )) -ge 0 ]
do
    "$@"
done
}

Po trzecie, zamknij i ponownie otwórz terminal lub wpisz:

$ source ~/.bash_aliases

Gotowe ! Możesz teraz używać tego w następujący sposób:

$ repeat 5 echo Hello World !!!

lub

$ repeat 5 ./myscript.sh

w linii xdg-open ~ / .bash-aliasses jest mała literówka. powinno być: xdg-open ~ / .bash_aliases (tj.: podkreślenie)
— ssinfod

4

możesz użyć crontab. uruchom polecenie crontab -ei otwórz je za pomocą preferowanego edytora tekstu, a następnie dodaj ten wiersz

*/10 * * * *  /path-to-your-command

Spowoduje to uruchomienie polecenia co 10 minut

* */4 * * *  /path-to-your-command

Spowoduje to uruchomienie polecenia co 4 godziny

Inne możliwe rozwiązanie

$ ..some command...; for i in $(seq X); do $cmd; sleep Y; done

X liczbę powtórzeń.

Y czas oczekiwania powtórzyć.

Przykład:

$ echo; for i in $(seq 5); do $cmd "This is echo number: $i"; sleep 1;done

Dlaczego to poprawa? Właśnie dodałeś dodatkowy, niepotrzebny krok, zapisując polecenie jako zmienną. Jedyne, co to robi, to: i) wydłużenie wpisywania ii) zmusza cię do używania tylko prostych poleceń, bez potoków i przekierowań itp.
— terdon

Usuń dodatkową zmienną
— Maythux

3

Innym problemem związanym z zaproponowanym powyżej podejściem „obserwuj” jest to, że wyświetla wynik dopiero po zakończeniu procesu. „date; sleep 58; date” wyświetli 2 daty dopiero po 59 sekundach ... Jeśli zaczniesz coś działać przez 4 minuty, które wyświetlają powoli wiele stron treści, tak naprawdę nie zobaczysz.

Z drugiej strony, problem związany z podejściem „while” polega na tym, że nie bierze on pod uwagę czasu trwania zadania.

while true; do script_that_take_between_10s_to_50s.sh; sleep 50; done

Dzięki temu skrypt będzie uruchamiany co minutę, czasem może zająć 1m40. Więc nawet jeśli cron będzie mógł uruchamiać go co minutę, tutaj nie będzie.

Aby więc zobaczyć wynik w powłoce podczas generowania i poczekać na dokładny czas żądania, musisz spojrzeć na czas przed i po oraz zapętlić się z chwilą.

Coś jak:

while ( true ); do
  echo Date starting `date`
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))`
  echo Before waiting `date`
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
  echo Done waiting `date`
done

Spowoduje to wygenerowanie:

Jak widać, polecenie jest uruchamiane co minutę:

Date starting Mon Dec 14 15:49:34 EST 2015
Before waiting Mon Dec 14 15:49:52 EST 2015
Done waiting Mon Dec 14 15:50:34 EST 2015

Date starting Mon Dec 14 15:50:34 EST 2015
Before waiting Mon Dec 14 15:50:39 EST 2015
Done waiting Mon Dec 14 15:51:34 EST 2015

Więc po prostu zamień echo $(( ( RANDOM % 30 ) + 1 ))komendę „uśpienie ” na to, co chcesz, i będzie ono uruchamiane na terminalu / powłoce dokładnie co minutę. Jeśli chcesz mieć inny harmonogram, po prostu zmień „60” sekund na to, czego potrzebujesz.

Krótsza wersja bez linii debugowania:

while ( true ); do
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))` # Place you command here
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
done

Odpowiadanie sobie ... Jeśli twoje polecenie zajmie więcej niż skonfigurowane opóźnienie, $ DELAY otrzyma wartość ujemną, a polecenie uśpienia zakończy się niepowodzeniem, więc skrypt natychmiast uruchomi się ponownie. Musisz być tego świadomy.
— jmspaggi
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.