Աղջիկը և նրա բառը. Լեզվի վերափոխման հիմունքները

ghostinushanka, քպելով կոճակները անցած 20 րոպեի ընթացքում, կարծես թե, դա նրա կյանքի վրա էր ազդում, նա շրջվում է ինձ hacia անհասկանալի հայացքով և չարություն վերցնող ժպիտով՝ «Մարդ, կարծես թե ես դա հասկանում եմ»։

«Դիտիր այստեղ»՝ ասում է՝ ցույց տալով էկրանին նախկինում նշված նշանի վրա՝ «Նրանք խաղում են իմ կարմիր գլխարկի վրա, որ նկատենք, որ եթե մենք այստեղ ավելացնենք այն, ինչ刚刚 ուղարկեցի», ցույց տալով մեկ այլ կոդի հատվածի վրա՝ «նման խնդիրը խուսանավելի չի լինի»։

Թ sedikit պակաս, ես փոխում եմ sed արտահայտությունը, որի վրա մենք որոշ ժամանակ աշխատել ենք, պահում եմ ֆայլը և սկսում systemctl varnish reload. Ошибка исчезла…

«Մեյլները, որոնք ես փոխանակում էի թեկնածուի հետ»՝ շարունակեց իմ colega, mientras su sonrisa se convierte lentamente en una genuina sonrisa llena de alegría, «De repente me di cuenta de que esta era exactamente la misma проблема!»

Ինչից սկսվել է սա

Հոդվածը ենթադրում է bash-ի, awk-ի, sed-ի և systemd-ի աշխատանքի սկզբունքների հասկանալություն։ Varnish-ի գիտելիքը ցանկալի է, բայց պարտադիր չէ։
Ժամանիշները հանձնված են snippets-ում։
Հեղինակված է միասին ghostinushanka.
Այս տեքստը թարգմանություն է 2 շաբաթ առաջ հրապարակված անգլերեն բնօրինակից; թարգմանություն boikoden.

Արևը շատալնում է ուսումնական պատուհաններից մեկ, մի ջերուի հատուկ բույրը կայանում է ստեղնաշարի կողքին, ականջակալներում լսվում է սիրելի սիմֆոնիան, որ խանգարում է մեխանիկական ստեղնաշարերի շռնդին, իսկ առաջին գրառումը բեքլոգի ստեցումում ուրախությամբ թեփ չէ՝ «Փնտրեք varnishreload sh: echo: I/O error in staging» (Պարզեք «varnishreload sh: echo: I/O error» ստադակի մեջ). Երբ խոսքը վերաբերում է varnish-ին, սխալներին տեղ չունի, անգամ ի վիճակի նրանց չեն լինելու տարօրինակ շեղումներ։

Նրանց համար, ովքեր ծանոթ չեն varnishreload, սա պարզ շելլային սքրիպտ է, որը օգտագործվում է varnish-ի հարցումները վերականգնելու համար -ը, որը նաև կոչվում է VCL։ Ինչպես նշված է թերթի անունով, սխալը առաջացել է մի սերվերի վրա ստադում, և քանի որ ես վստահ էի, որ varnish-ի երթևեկությունը ստադում են աշխատում, մտածեցի, որ սա կլինի մի փոքր սխալ: Եվ դա կլինի պարզապես հաղորդագրություն, որը հայտնվել է արդեն փակված ելքագրի մեջ։ Օրենքը վերցնում եմ ինձ և լիովին վստահ եմ, որ ես հաշվարկելու եմ դրան պիտանի ավելի քիչ քան 30 րոպեներ, ծափ տալիս եմ ինքս ինձ ափի վրա զգացողության մեջ, որ հարցերը վերադարձնում եմ վիճակագրությունից և ետ վերադառնում մյուս կարևոր աշխատանքներին:

200 կմ/h արագությամբ խփելով պատին

Ներդրումելով ֆայլը

, մի թվային սերվերում, որը շահարկվում է Debian Stretch-ով, ես տեսնում եմ մի շելլային սքրիպտ, որն ունի 200-ից պակաս տող։ varnishreloadՍքրիպտի շուրջ անցնելով, ես չտեսնեմ ոչ մի բան, որը կարող էր առաջացնել հարցեր մի քանի անգամ այն անմիջապես ծայրից:

այս ընթացքում դիտարկում անել։

Վերջում, սա է ստիջ, նույնիսկ եթե դա փչանա, ոչ ոք չի բողոքելու, լավ... ոչ շատ։ Ես запускаю скрипт и смотрю что будет выписываться на терминал, вот только ошибок уже и не видно.

Երկու մեկնարկ, վստահելու համար, որ չեմ կարող կրկնել սխալը առանց որևէ լրացուցիչ ուժեր, և ես սկսում եմ մտածել, թե ինչպես պետք է այդ скрипт-ը փոխեմ և ստիպեմ, որ այն կրկին արձանագրի սխալը։

Որովհետև скрипту перекрыть STDOUT (с помощью > &-)? Որո՞նցըք մնաց ոչ մեկ, ու ոչ ոք՝ ни то ни другое в итоге не сработало.

Ամեն ինչ, systemd каким-то образом изменяет среду запуска, но как, и почему?
Ես բացում եմ vim և խմբագրում եմ varnishreload, добавляя set -x ուղղակի шебанг-ի տակ, հույս ունենալով, что дебаг вывод скрипта прольёт чуточку света.

Ֆայլը խմբագրված է, ուստի ես վերագործարկում եմ varnish-ն ու տեսնում, որ փոփոխությունը միանգամից բոլորովին փչացավ… Արտահոսք — լիքը խառնաշփոթում, որտեղ հազարավոր C-կապակցված կոդեր։ Ամբողջ տերմինալում շրջելու համար բավական է, որպեսզի գտնել, որտեղ դա սկսվում է։ Ես լիովին խառնաշփոթի մեջ եմ։ Կարո՞ղ է, որ debugging режимը ազդի скрипտում запускаемых программ? Ոչ, հիմարություն։ Shell-ում սխալ կա՞։ Մի քանի հնարավոր սցենարներ փախչում են իմ գլխում, ինչպես տափոնները՝ տարբեր կողմերին։ Կոֆեինով լի գ杯ը անմիջապես դատարկվում է, արագ ճանապարհորդություն խոհանոց՝ տրամադրելու համար, և… գնացինք։ Ես բացում եմ скрипտը և ուշադիր ուսումնասիրում шебанг-ը: #!/bin/sh.

/bin/sh — դա ведь просто симлинк на bash, так что скрипт интерпретируется в POSIX-совместимом режиме, верно? Не тут-то было! Оболочка по умолчанию в Debian — это dash, и это именно то, на что ссылается /bin/sh.

# ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 24  2017 /bin/sh -> dash

Ես փորձի համար փոխեցի шебанг-ը на #!/bin/bash, удалил set -x и попробовал ещё раз։ Н наконец-то, при последующей перезагрузке varnish-а, в выводе появилась сносная ошибка:

Jan 01 12:00:00 hostname varnishreload[32604]: /usr/sbin/varnishreload: line 124: echo: write error: Broken pipe
Jan 01 12:00:00 hostname varnishreload[32604]: VCL 'reload_20190101_120000_32604' compiled

Строка 124, вот оно!

114 find_vcl_file() {
115         VCL_SHOW=$(varnishadm vcl.show -v "$VCL_NAME" 2>&1) || :
116         VCL_FILE=$(
117                 echo "$VCL_SHOW" |
118                 awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}' | {
119                         # all this ceremony to handle blanks in FILE
120                         read -r DELIM VCL_SHOW INDEX SIZE FILE
121                         echo "$FILE"
122                 }
123         ) || :
124
125         if [ -z "$VCL_FILE" ]
126         then
127                 echo "$VCL_SHOW" >&2
128                 fail "failed to get the VCL file name"
129         fi
130
131         echo "$VCL_FILE"
132 }

Բայց ինչպես պարզվեց, строка 124 довольно пуста и интереса не представляет. Я мог лишь только предположить, что ошибка возникла как часть многострочника, начинающегося на 116-й строке.
Что в итоге записывается в переменную VCL_FILE в результате выполнения вышеупомянутого саб-шелла?

В начале, он отправляет содержимое переменной VLC_SHOW, созданной на строке 115, следующей команде через пайпу. А там-то что тогда происходит?

Во-первых, там используется varnishadm, который является частью установочного пакета varnish, для настройки varnish-а без перезапуска.

հրավիրված խումբ vcl.show -v օգտագործվում է VCL-ի ամբողջական կոնֆիգուրացիան ցույց տալու համար, որը նշված է ${VCL_NAME}, STDOUT-ում.

Ուղղակի ցուցադրվող ակտիվ VCL կոնֆիգուրացիան, ինչպես նաև մի քանի նախորդ վառացման կոնֆիգուրացիաներ, որոնք դեռ հիշողության մեջ են, կարող եք օգտագործել հրամանով varnishadm vcl.list, որի արտահոսքը կլինի նման առաջադիմականի:

մերժված   սառը/բ occupied       1 reload_20190101_120000_11903
մերժված   սառը/բ occupied       2 reload_20190101_120000_12068
մերժված   սառը/բ occupied       16 reload_20190101_120000_12259
մերժված   սառը/բ occupied       16 reload_20190101_120000_12299
մերժված   սառը/բ occupied       28 reload_20190101_120000_12357
ակտիվ      ավտոմատ/տաք       32 reload_20190101_120000_12397
 availability   ավտոմատ/տաք       0 reload_20190101_120000_12587

փոխօգնության արժեքը ${VCL_NAME} նվիրվում է արտադրման մեկ այլ մասում varnishreload ակտիվ VCL-ի անունին, եթե կա: Այս դեպքում դա կլինի “reload_20190101_120000_12397”։

Ամեն ինչ պարզ է, փոխօգնության ${VCL_SHOW} ապահովում է լիարժեք կոնֆիգուրացիան varnish-ի համար, մինչդեռ պարզ է: Այժմ վերջապես հասկացա, թե ինչու dash-ի արտահոսքը set -x նման հեշտ տուժող դուրս էր եկել, քանի որ այն ներառում էր կազմված կոնֆիգուրացիայի պարունակությունը:

Ինքնըստինք, VCL-ի լիարժեք կոնֆիգուրացիան հաճախ կարող է ձևավորված լինել մի քանի ֆայլերից: C ոճի մեկնաբանություններ օգտագործվում են որոշելու համար, թե որտեղ են մեկ կոնֆիգուրացիայի ֆայլերն այլ ֆայլերում ներառվել, իսկ հենց սա է, ինչ որի վերաբերյալ ստորոն մեջնարկված կոդի հատվածը:
Նշման հիմնառումները, որոնք նկարագրում են ներառված ֆայլերը, հետևյալ ձևաչափն ունեն:

// VCL.SHOW <NUM> <NUM> <FILENAME>

Թվերը այս համատեքստում աննշան են, մեզ հետաքրքրում է ֆայլի անունը:

Իրականում, ինչ է կատարվում 116-րդ տողից սկսած հրամաններում:
Եկեք պարզենք:
Հրամանը բաղկացած է չորս մասից՝

  1. Անկեղծ echo, որը ցույց է տալիս փոխօգնության արժեքը: ${VCL_SHOW}
    echo "$VCL_SHOW"
  2. awk, որը փնտրում է տող (առնչություն), որտեղ առաջին դաշտը, տեքստը բաժանելուց հետո, կլինի “//”, իսկ երկրորդը՝ «VCL.SHOW»
    Awk-ն կառաջարկի առաջին տողը, որը համապատասխանելու է այդ դիմաչիներին, այնուհետև անմիջապես կդադարեցնի մշակումը:
    awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}'
  3. Կոդի բլոկ, որը պահում է հինգ փոխօգնության արժեքները, բաժանված միջակայքերով: Կեսրարման ամբառնիը `FILE` ստանում է տողի մնացած մասը: Վերջապես, վերջին echo-ն թողնել է փոխօգնությունը: ${FILE}.
    { read -r DELIM VCL_SHOW INDEX SIZE FILE; echo "$FILE" }
  4. Քանի որ 1-ից 3 քայլերը գտնվում են ենթա-թևում, արտահոսքը $FILE պիտի գրանցվի փոխօգնության մեջ: VCL_FILE.

Ինչպես 119-րդ տողի մեկնաբանությունն ասում է, սա ծառայում է միայն մեկ նպատակին. հուսով լինել, երբ VCL-ն կկապվի անվանումների մեջ, որտեղ կա տարածություն:

Ես մեկնաբանեցի սկզբանու տրամաբանությունը մշակման համար ${VCL_FILE} և փորձեցի փոխել հրcommands-ը, բայց դա ոչ մի արդյունք չտվեց: Ես ամլել եմ բոլորը պարզ, իսկ ծառայության սկսելու դեպքում՝ սխալը։

Եկեք ասենք, որ սխալը պարզապես չի կրկնվում ձեռքով սկրիպտը գործարկելուց, մինչդեռ ենթադրյալ 30 րոպեն արդեն ավարտվել է վեց անգամ, և բացի այդ, muncul более առաջնային խնդիր, որը բերել է մյուս գործերը մի կողմ։ Հաճախակի շաբաթը լեցուն էր տարբեր խնդիրներով, ընդամենը փոքր-ինչ օգնում էր sed-ի մասին զեկույցը և թեկնածուի հարցազրույցը։ Սխալի հարցում varnishreload վերջնականապես կորցվել է ժամանակի ավազներում։

Ձեր այսպես կոչված sed-fu… իրականում… սարսափ է։

Շաբաթը մեկ բավական ազատ օր էր, և ես ևս մեկ անգամ որոշեցի զբաղվել այս թիկետով։ Հույս ունեի, որ իմ ուղեղի մեջ, որևէ ֆոնային գործընթաց քննում էր այս խնդրի լուծումը, և այս անգամ ես արդեն հաստատ կգիտեի, թե ինչն է։

Կանխատեսված վերջին անգամ պարզապես կոդի փոփոխությունը չի օգնել, ես պարզապես որոշեցի ստուգել դա 116-րդ տողից սկսելով։ Ինձնից առկա կոդը իսկապես հիմար էր։ Եվ դրա մեջ որևէ անհրաժեշտություն չուներ օգտագործել read.

Սխալին ևս մեկ անգամ նայելով։
sh: echo: broken pipe — այս հրամանով echo-ն գտնվում է երկու տեղում, բայց ես կասկածում եմ, որ առաջինը ավելի հավանական մեղավոր է (այլ խոսքով, գոնե համասեռակից)։ Awk-ն ևս չի վստահեցնում։ Եվ եթե դա իսկապես awk | {read; echo} կառույցը բերում է այս բոլոր խնդիրներին, ինչու մեկ այլ չէ փոխել այն։ Այս մեկ տողի հրամանն օգտագործում է awk-ի բոլոր հնարավորությունները, և ավելին read շրջանից։

Քանի որ անցյալ շաբաթ անցկացվեց զեկույց sed, ես ցանկանում էի փորձարկել իմ վերջերս ստացած հմտությունները և պարզեցնել echo | awk | { read; echo} նաև ավելի պարզ echo | sed։ Չնայած դա հաստատ չի հանդիսանում սխալը հայտնաբերելու լավագույն մոտեցումը, ես մտածեցի, որ գոնե փորձեմ իմ sed-fu-ն և, հնարավոր է, նոր բան իմանամ խնդրի վերաբերյալ։ Արդյունքում, ես խնդրեցի իմ գործընկերոջը, sed-ի զեկույցի հեղինակին, օգնելս մտածել ավելի արդյունավետ sed սկրիպտ կազմելու համար։

Ես փոխանցեցի պարունակությունը varnishadm vcl.show -v "$VCL_NAME" ֆայլում, որպեսզի կարողանամ կենտրոնանալ sed սկրիպտի գրելուն առանց ծառայության վերագործարկման հետ կապված խանգարումների։

Sed-ի մուտքային տվյալները մշակելու վերաբերյալ համառոտ նկարագրությունը կարելի է գտնել անունով GNU մարդու աշխատության մեջ.Sed-ի աղբյուրային কোդে նշվում է n հստակորեն որպես տողերի բաժանարար։

Որոշ անցումների ընթացքում և իմ գործընկերոջ առաջարկություններով մենք մշակեցինք sed սկրիպտ, որը տալիս էր նույն արդյունքը, ինչ 116-րդ հիմնական տողը։

Հետևեցնում ենք մուտքային տվյալների նմուշ ֆայլը.

> cat vcl-example.vcl
Text
// VCL.SHOW 0 1578 file with 3 spaces.vcl
More text
// VCL.SHOW 0 1578 file.vcl
Even more text
// VCL.SHOW 0 1578 file with TWOspaces.vcl
Final text

Այդ վերոթարկման համար հավաքված նկարագրությունը, սակայն կարևոր է միայն առաջին մեկնաբանությունը, // VCL.SHOWորը մտքի հաճախորդի կնքող է, կարևորը մուտքային տվյալներում կարող են լինել մի քանի։ Դա իշխանություն է, որ այդ վաճառվող awk-ն ավարտվում է առաջին համընկմամբ։

# шаг первый, вывести только строки с комментариями
# используя возможности sed, определяется символ-разделитель с помощью конструкции '#' вместо обычно используемого '/', за счёт этого не придётся экранировать косые в искомом комментарии
# определяется регулярное выражение “// VCL.SHOW”, для поиска строк с определенным шаблоном
# флаг -n позаботится о том, чтобы sed не выводил все входные данные, как он это делает по умолчанию (см. ссылку выше)
# -E позволяет использовать расширенные регулярные выражения
> cat vcl-processor-1.sed
#// VCL.SHOW#p
> sed -En -f vcl-processor-1.sed vcl-example.vcl
// VCL.SHOW 0 1578 file with 3 spaces.vcl
// VCL.SHOW 0 1578 file.vcl
// VCL.SHOW 0 1578 file with TWOspaces.vcl

# шаг второй, вывести только имя файла
# используя команду “substitute”, с группами внутри регулярных выражений, отображается только нужная группa
# и это делается только для совпадений, ранее описанного поиска
> cat vcl-processor-2.sed
#// VCL.SHOW# {
    s#.* [0-9]+ [0-9]+ (.*)$#1#
    p
}
> sed -En -f vcl-processor-2.sed vcl-example.vcl
file with 3 spaces.vcl
file.vcl
file with TWOspaces.vcl

# шаг третий, получить только первый из результатов
# как и в случае с awk, добавляется немедленное завершения после печати первого найденного совпадения
> cat vcl-processor-3.sed
#// VCL.SHOW# {
    s#.* [0-9]+ [0-9]+ (.*)$#1#
    p
    q
}
> sed -En -f vcl-processor-3.sed vcl-example.vcl
file with 3 spaces.vcl

# шаг четвертый, схлопнуть всё в однострочник, используя двоеточия для разделения команд
> sed -En -e '#// VCL.SHOW#{s#.* [0-9]+ [0-9]+ (.*)$#1#p;q;}' vcl-example.vcl
file with 3 spaces.vcl

Այսպես, varnishreload սցենարի բովանդակությունը մի քանի ամենահավանական տեսքով կ выглядить:

VCL_FILE="$(echo "$VCL_SHOW" | sed -En '#// VCL.SHOW#{s#.*[0-9]+ [0-9]+ (.*)$#1#p;q;};')"

Ներքևում նշված տրամաբանությունը կարող է ամփոփել հետևյալ կերպ:
Եթե բնակարանն համապատասխան է կանոնավոր արտահայտությանը, // VCL.SHOW, ապա ագրեսիվ կուլ տուր տեքստը, որն ընդգրկում է երկու թվերը այս տողում, և պահիր ամեն բան, ինչը կմնա այս գործողությունից հետո։ Երջանիկ պահված արժեքը վերադարձրու և ավարտի ծրագիրը։

Սովորական է, չի՞:

Մենք գոհ էինք sed սցենարից և այն փաստից, որ այն փոխարինում է ամբողջ սկզբնական կոդը։ Իմ բոլոր փորձարկումները տվեցին ցանկալի արդյունքներ, ուստի ես փոփոխեցի "varnishreload" սերվերի վրա և կրկին առաջացրեցի systemctl reload varnish. Սարսափելի սխալ echo: գրելու սխալ: Broken pipe վերնիս կրկին ծիծաղում էր մեր դեմ։ Սողացող կուրսորը սպասում էր նոր հրահանգի մուտքի մութ դատարկության մեջ…

Ընտանիք: habr.com

Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster