Ինչպե՞ս (և ինչու) կանխել Bash սցենարի վերագործարկումը շատ շուտով


Արագ հղումներ

  • Շունչ քաշեք
  • Մեր ժամանակի վրա հիմնված ռազմավարությունը
  • Ժամանակը Linux-ում
  • Ժամանակի պահպանում և առբերում
  • Ամեն ինչ միասին դնելը
  • Օգտակար այլ սցենարներում

Երբեմն օգտակար է համոզվել, որ Bash shell սցենարը շատ հաճախ չի աշխատում: Ահա մի կոկիկ միջոց՝ սահմանելու ժամանակի սահմանափակում, որը պետք է ավարտվի, նախքան սցենարը նորից գործարկվի:

Շունչ քաշեք

Կախված նրանից, թե ինչ է նա անում և ինչ այլ գործընթացներ կարող է գործարկել, Bash սկրիպտը կարող է սպառել այնքան RAM և CPU ժամանակ, որքան ցանկացած այլ ռեսուրսների կարիք ունեցող գործընթաց: Կարող է օգտակար լինել սահմանափակել, թե որքան հաճախ կարող է գործարկվել նման սցենար:

Ծանր քաշային սցենարի յուրաքանչյուր գործարկման միջև դադարի պարտադրումը խանգարում է նրան ռեսուրսների կուտակմանը: Հաշվարկային առումով թանկ սկրիպտները կարող են մոնոպոլիզացնել համակարգիչներն այն աստիճան, երբ մյուս օգտվողները կատարողականի անկում են զգում: Ծայրահեղ դեպքերում, եթե սկրիպտը, օրինակ, սկավառակի մեծ աղմուկի պատճառ է դառնում, այն կարող է նույնիսկ արագացնել ձեր սարքաշարի մահը:

Իհարկե, մի սխեմայի նախագծումը, որը սահմանափակում է, թե որքան շուտ կարող եք վերագործարկել սկրիպտը, ավելացնում է կոդը ձեր սցենարին և տալիս է ևս մեկ անելիք: Դա կարող է հակաարդյունավետ թվալ, բայց եթե չեկերը թեթև և արագ են, ապա դրանց չնչին ծախսերը զգալիորեն գերազանցում են իրենց ռեսուրսների խնայողությունները:

Մեր ժամանակի վրա հիմնված ռազմավարությունը

Մենք ցանկանում ենք կիրառել նվազագույն ժամանակաշրջան, որը պետք է ավարտվի մինչև սցենարը կրկնվի: Մենք այս շրջանը կանվանենք միջանկյալ: Մենք դա կսահմանենք որպես նախորդ վազքի ավարտի և նոր վազքի մեկնարկի միջև ընկած ժամանակահատվածը:

Մենք պետք է խնայենք սցենարի ավարտի ժամանակը, որպեսզի հաջորդ անգամ, երբ սկրիպտը գործարկվի, կարողանանք առբերել այն: Քանի որ սցենարը հեշտությամբ կարող է որոշել ընթացիկ ժամանակը, այն կարող է որոշել իր գործարկման ժամանակի և նախորդ սցենարի ավարտի ժամանակի տարբերությունը:

Եթե այդ տարբերությունը մեր ընդունելի միջանկյալից փոքր է, սցենարը դուրս կգա:

Ժամանակը Linux-ում

Linux-ը վայրկյաններ է հաշվում Linux-ի (երկրորդ) դարաշրջանից, որը տեղի ունեցավ 1970թ. հունվարի 1-ի կեսգիշերին, UTC: Մենք կարող ենք տեսնել ժամը և ամսաթիվը, թողարկելով ամսաթիվ հրամանը:

date

Մենք կարող ենք մինչև օրս փոխանցել ձևաչափի սպեցիֆիկատորներ՝ տարբեր արտապատկերումներով արդյունք ստանալու համար: Դարաշրջանից սկսած ժամանակը վայրկյաններով տեսնելու համար օգտագործեք փոքրատառ «s».

date +%s

Ժամանակը որպես մեկ ամբողջ թիվ մուտք գործելու հնարավորությունը շատ հեշտ է դարձնում երկու անգամների համեմատությունը և դրանց միջև ընկած ժամանակահատվածը պարզելը: Դա կատարյալ է մեր կարիքների համար, և մենք լավ կօգտագործենք դա:

Ժամանակի պահպանում և առբերում

Մենք հեշտությամբ կարող ենք ժամանակը գրել ֆայլի մեջ՝ պարզապես վերահղելով ամսաթիվ հրամանի ելքը: Մենք կարող ենք օգտագործել կատուն՝ ստուգելու համար, որ այն աշխատել է:

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

Դա մեզ հնարավորություն է տալիս պահելու մեր ժամանակացույցը: Նկատի ունեցեք, որ մենք օգտագործում ենք մեկ > վերահղման համար, այնպես որ ֆայլը ամեն անգամ վերստեղծվում է, և երբևէ պահում է միայն մեկ մուտք:

Մեր սցենարի ներսում մենք պետք է բացենք ժամանակի դրոշմակնիքի ֆայլը և կարդանք պահպանված արժեքը: Այդ արժեքը պետք է պահվի փոփոխականում, որպեսզի մեր սցենարը կարողանա օգտագործել այն:

Դա բավականին ներգրավված է թվում, բայց կա մի պարզ հնարք, որը մենք կարող ենք օգտագործել: Մեր սցենարի ներսում մենք կօգտագործենք աղբյուրի հրամանը՝ ժամանակի դրոշմակնիքի ֆայլը կարդալու համար: Աղբյուրի ֆայլի ներսում հրամանները կատարվում են այնպես, կարծես դրանք հրամաններ լինեն մեր սցենարի ներսում:

Երբ մենք պահպանում ենք ժամանակի դրոշմը, մենք իրականում կպահենք հրաման, որը ստեղծում է փոփոխական և դրան տալիս է ժամանակի արժեքը: Երբ ֆայլը սկզբնավորվում է, մեր սցենարը կկատարի այդ հրամանը, կստեղծի փոփոխականը և ժամանակի արժեքը կպահի փոփոխականում, այնպես որ ամեն ինչ արված է մեզ համար:

Մենք կարող ենք ստուգել այդ գործընթացը հրամանի տողում: Մենք հրաման ենք կազմում և գրում ֆայլում: Հրամանը ստեղծում է փոփոխական, որը կոչվում է previous_exit, որը սահմանված է դարաշրջանից սկսած վայրկյանների քանակով: Մենք աղբյուր ենք ֆայլը. Այնուհետև մենք ստուգում ենք, որ previous_exit կոչվող փոփոխականն այժմ գոյություն ունի և տեսնենք, թե ինչ արժեք է այն պահպանում:

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

Եթե մենք ուսումնասիրենք ֆայլի բովանդակությունը, կարող ենք ստուգել, որ փոփոխականի կողմից պահվող արժեքը ֆայլում եղած արժեքն է:

cat timestamp.log 

Սա լավ և հեշտ լուծում է մեր ժամանակի արժեքը պահելու և առբերելու համար:

Ամեն ինչ միասին դնելը

Եկեք անցնենք սցենարի տարբեր տարրերին:

Իմ սցենարը կպահի ժամանակի դրոշմակնիքները .timestamp.log կոչվող ֆայլում: Նկատի ունեցեք, որ առաջին նիշը «.» կետն է, ինչը նշանակում է, որ այն թաքնված ֆայլ է: Այն կպահվի իմ գլխավոր գրացուցակում:

Սցենարը ստեղծում է փոփոխական, որը կոչվում է timestamp_log՝ ուղին և ֆայլի անունը պահելու համար:

Հաջորդը սահմանվում է set_timestamp կոչվող ֆունկցիան: Երբ այն կանչվում է, այս ֆունկցիան գրում է իրեն փոխանցված արժեքը՝ timestamp.log ֆայլում։

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

Քանի որ timestamp.log ֆայլը թարմացվում է (և ստեղծվում է, եթե այն գոյություն չունի), երբ սկրիպտը դուրս է գալիս, հենց առաջին անգամ, երբ սկրիպտը գործարկվում է, timestamp.log ֆայլը գոյություն չի ունենա: Դա խնդիր կառաջացնի, երբ սցենարը փորձի կարդալ դրանից:

Այդ խնդիրը հաղթահարելու և այն իրավիճակներից պաշտպանվելու համար, երբ timestamp.log ֆայլը կարող էր ջնջվել, մենք ստուգում ենք ֆայլի առկայությունը: Եթե այն գոյություն չունի, մենք այն ստեղծում ենք՝ դրանում զրոյական կեղծ ժամանակային արժեք պահելով:

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

Այժմ մենք կարող ենք ապահով կերպով սկզբնավորել ֆայլը և կարդալ դրա ներսի հրահանգը: Սա նախորդ_ելքի փոփոխականը սահմանում է նախորդ ժամանակի դրոշմանիշին:

# get the last exit time as 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
# your actual script starts here 
echo "Running..."

Եթե միջանկյալ ժամանակահատվածը հինգ վայրկյանից ավելի է, սցենարը կարող է շարունակվել: Երբ այն ավարտվի, մենք ընթացիկ ժամանակը գրում ենք timestamp.log ֆայլում՝ զանգահարելով մեր set_timestamp ֆունկցիան:

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

Ահա ամբողջ սցենարը.

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

Պատճենեք սա ձեր սիրած խմբագրի մեջ և պահեք որպես tc.sh անունով ֆայլ: Հիշեք, որ փոխեք timestamp_log= արժեքը 4-րդ տողում՝ ցույց տալու համար ձեր համակարգչի այն վայրը, որտեղ պետք է պահվի timestamp.log-ը:

Դարձրեք ձեր սցենարը գործարկելի:

chmod +x tc.sh

Եվ հիմա մենք կարող ենք այն գործարկել:

./tc.sh

Հետագա մահապատժի փորձերը հինգ վայրկյան բացառման ժամկետի ընթացքում ինքնադադարում են: Հինգ վայրկյանից հետո մենք կարող ենք նորից գործարկել սցենարը:

Օգտակար այլ սցենարներում

Հիշեք, եթե ձեր սկրիպտը ճյուղավորվող կատարում է և կարող է դուրս գալ սկրիպտի տարբեր կետերից, դուք պետք է զանգահարեք set_timestamp-ը յուրաքանչյուր հնարավոր ելքից առաջ: Ահա թե ինչու արժե ստեղծել set_timestamp ֆունկցիան, թեև այս սկրիպտում այն օգտագործվում է ընդամենը երկու անգամ:

Փոփոխականի անունը և դրա արժեքը պահելու հնարքը աղբյուրից ստացված ֆայլում կարող է օգտագործվել կոնֆիգուրացիայի ֆայլում կարդալու համար: Դուք պարզապես պետք է գրեք փոփոխականների անունների և դրանց արժեքների ցուցակը ֆայլում և այն ձեր սկրիպտից: