Ako (a prečo) zabrániť príliš skorému opätovnému spusteniu Bash skriptu


Rýchle odkazy

  • Vydýchnite si
  • Naša stratégia založená na čase
  • Čas v Linuxe
  • Ukladanie a získavanie času
  • Dať to všetko dokopy
  • Užitočné v iných scenároch

Niekedy je užitočné uistiť sa, že skript shellu Bash sa nespúšťa príliš často. Tu je elegantný spôsob, ako nastaviť časový limit, ktorý musí uplynúť, kým sa skript znova spustí.

Vydýchnite si

V závislosti od toho, čo robí a ktoré ďalšie procesy môže spustiť, môže skript Bash spotrebovať toľko pamäte RAM a času CPU ako ktorýkoľvek iný proces náročný na zdroje. Môže byť užitočné obmedziť frekvenciu spúšťania takéhoto skriptu.

Vynútenie obdobia oddychu medzi každým spustením náročného skriptu ho zastaví v zabíjaní zdrojov. Výpočtovo drahé skripty môžu monopolizovať počítače do tej miery, že ostatní používatelia zaznamenajú pokles výkonu. V extrémnych prípadoch, ak skript napríklad spôsobí veľa diskov, môže dokonca urýchliť zánik vášho hardvéru.

Samozrejme, vytvorenie schémy, ktorá obmedzuje, ako skoro môžete skript znovu spustiť, pridá kód do vášho skriptu a dá mu ešte jednu vec. To môže znieť kontraproduktívne, ale ak sú šeky ľahké a rýchle, ich malé režijné náklady výrazne prevážia ich úspory zdrojov.

Naša stratégia založená na čase

Chceme presadiť minimálne časové obdobie, ktoré musí uplynúť pred opakovaním skriptu. Toto obdobie nazývame prechodné. Definujeme ho ako čas medzi ukončením predchádzajúceho cyklu a začiatkom nového cyklu.

Musíme si uložiť čas, kedy sa skript dokončí, aby sme ho pri ďalšom spustení mohli znova získať. Keďže skript dokáže ľahko určiť aktuálny čas, dokáže zistiť rozdiel medzi časom spustenia a časom ukončenia predchádzajúceho skriptu.

Ak je tento rozdiel menší ako naše prijateľné obdobie, skript sa ukončí.

Čas v Linuxe

Linux počíta sekundy od (druhej) epochy Linuxu, ktorá sa stala o polnoci 1. januára 1970 v UTC. Čas a dátum môžeme vidieť zadaním príkazu dátum.

date

Do dnešného dňa môžeme zadať špecifikátory formátu, aby sme získali výstup v rôznych vykresľovaniach. Ak chcete zobraziť čas v sekundách od epochy, použite malé písmeno „s“:

date +%s

Vďaka možnosti prístupu k času ako jedinému celému číslu je veľmi jednoduché porovnať dva časy a zistiť časové rozpätie medzi nimi. To je ideálne pre naše potreby a my to dobre využijeme.

Ukladanie a získavanie času

Čas môžeme jednoducho zapísať do súboru, a to len presmerovaním výstupu príkazu date. Môžeme použiť mačku na overenie, že to fungovalo.

date +%s > temp.dat
cat temp.dat

To nám dáva spôsob, ako uložiť našu časovú pečiatku. Všimnite si, že na presmerovanie používame jediné >, takže súbor sa zakaždým vytvorí znova a vždy obsahuje iba jeden záznam.

V našom skripte musíme otvoriť súbor časovej pečiatky a prečítať uloženú hodnotu. Túto hodnotu je potrebné uchovávať v premennej, aby ju náš skript mohol použiť.

Znie to dosť komplikovane, ale môžeme použiť jednoduchý trik. V našom skripte použijeme príkaz source na čítanie súboru časovej pečiatky. Príkazy v zdrojovom súbore sa vykonávajú, ako keby to boli príkazy v našom skripte.

Keď uložíme časovú pečiatku, v skutočnosti uložíme príkaz, ktorý vytvorí premennú a priradí jej časovú hodnotu. Keď je súbor zdrojový, náš skript vykoná tento príkaz, vytvorí premennú a uloží hodnotu času do premennej, takže je to všetko hotové za nás.

Tento proces môžeme skontrolovať na príkazovom riadku. Zostavíme a zapíšeme príkaz do súboru. Príkaz vytvorí premennú s názvom previous_exit, ktorá je nastavená na počet sekúnd od epochy. Zdrojový kód súboru. Potom skontrolujeme, či premenná s názvom previous_exit teraz existuje, a uvidíme, akú hodnotu má.

echo "previous_exit=$(date +%s)" > timestamp.log
source timestamp.log
echo $previous_exit

Ak preskúmame obsah súboru, môžeme overiť, že hodnota, ktorú má premenná, je tá, ktorá je v súbore.

cat timestamp.log 

Je to pekné a jednoduché riešenie na ukladanie a získavanie našej časovej hodnoty.

Dať to všetko dokopy

Poďme si prejsť jednotlivé prvky skriptu.

Môj skript uloží časové pečiatky do súboru s názvom .timestamp.log. Všimnite si, že prvý znak je bodka „.“, čo znamená, že ide o skrytý súbor. Bude uložený v mojom domovskom adresári.

Skript vytvorí premennú s názvom timestamp_log, ktorá obsahuje cestu a názov súboru.

Ďalej je definovaná funkcia s názvom set_timestamp. Keď je zavolaná, táto funkcia zapíše hodnotu, ktorá jej bola odovzdaná, do súboru timestamp.log.

#!/bin/bash
# location of the timestamp log file
timestamp_log="/home/dave/.timestamp.log"
set_timestamp() {
  echo "previous_exit=$1" > $timestamp_log
}

Keďže súbor timestamp.log sa aktualizuje (a vytvorí sa, ak neexistuje), keď skript ukončí, pri prvom spustení skriptu súbor timestamp.log nebude existovať. To by spôsobilo problém, keď sa z neho skript pokúsil čítať.

Na prekonanie tohto problému a na ochranu pred situáciami, v ktorých mohol byť súbor timestamp.log odstránený, testujeme existenciu súboru. Ak neexistuje, vytvoríme ho uložením nulovej fiktívnej časovej hodnoty.

# If the timestamp log file doesn't exist, create it
if [ ! -f $timestamp_log ]; then
  set_timestamp 0
fi

Teraz môžeme bezpečne získať zdroj súboru a prečítať si pokyny v ňom. Toto nastaví premennú previous_exit na predchádzajúcu časovú značku.

# get the last exit time as variable called previous_exit
source $timestamp_log

Teraz, keď máme hodnotu časovej pečiatky, môžeme vypočítať prechodné obdobie medzi predchádzajúcou časovou pečiatkou a aktuálnym časom.

# get the interim period since the last exit
interim=$(( $(date +%s)-$previous_exit ))

Teraz môžeme vykonať jednoduchý test, aby sme zistili, či uplynul dostatok času na to, aby sa skript mohol spustiť. Na testovanie používam ľubovoľnú a krátku hodnotu piatich sekúnd.

if (( $interim <= 5 )); then 
  echo "Too soon... $interim seconds..."
  exit 1; 
fi
# your actual script starts here 
echo "Running..."

Ak je medzičas viac ako päť sekúnd, skript môže pokračovať. Po dokončení zapíšeme aktuálny čas do súboru timestamp.log volaním našej funkcie set_timestamp.

# set the new timestamp
set_timestamp $(date +%s)
exit 0

Tu je celý skript.

#!/bin/bash
# location of the timestamp log file
timestamp_log="/home/dave/.timestamp.log"
set_timestamp() {
  echo "previous_exit=$1" > $timestamp_log
}
# If the timestamp log doesn't exist, create it
if [ ! -f $timestamp_log ]; then
  set_timestamp 0
fi
# get the last exit time as a variable called previous_exit
source $timestamp_log
# get the interim period since the last exit
interim=$(( $(date +%s)-$previous_exit ))
if (( $interim <= 5 )); then 
    echo "Too soon... $interim seconds..."
  exit 1; 
fi
# set the new timestamp
set_timestamp $(date +%s)
echo "Running..."
exit 0

Skopírujte to do svojho obľúbeného editora a uložte ho ako súbor s názvom tc.sh. Nezabudnite zmeniť hodnotu timestamp_log= v riadku 4 tak, aby ukazovala na miesto vo vašom počítači, kde by sa mal súbor timestamp.log uložiť.

Urobte svoj skript spustiteľným.

chmod +x tc.sh

A teraz to môžeme spustiť.

./tc.sh

Následné pokusy o vykonanie v rámci päťsekundovej doby vylúčenia sa ukončia samy. Po uplynutí piatich sekúnd môžeme skript spustiť znova.

Užitočné v iných scenároch

Pamätajte, že ak váš skript vykonáva vetvenie a mohol by skončiť v rôznych bodoch skriptu, musíte pred každým možným ukončením zavolať set_timestamp. Preto sa oplatilo vytvoriť funkciu set_timestamp, aj keď sa v tomto skripte používa iba dvakrát.

Trik uloženia názvu premennej a jej hodnoty v súbore, ktorý je zdrojom, možno využiť na čítanie v konfiguračnom súbore. Budete len musieť napísať zoznam názvov premenných a ich hodnôt do súboru a získať ho zo skriptu.