Ինչպե՞ս (և ինչու) կանխել 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 ֆունկցիան, թեև այս սկրիպտում այն օգտագործվում է ընդամենը երկու անգամ:
Փոփոխականի անունը և դրա արժեքը պահելու հնարքը աղբյուրից ստացված ֆայլում կարող է օգտագործվել կոնֆիգուրացիայի ֆայլում կարդալու համար: Դուք պարզապես պետք է գրեք փոփոխականների անունների և դրանց արժեքների ցուցակը ֆայլում և այն ձեր սկրիպտից: