AWK ձեռնարկ. AWK հրամանի 25 գործնական օրինակներ Linux-ում
Զարմանում եք, թե ինչպես օգտագործել AWK հրամանը Linux-ում: Ահա AWK հրամանների 25 օրինակներ՝ պատշաճ բացատրությամբ, որոնք կօգնեն ձեզ տիրապետել AWK-ի հիմունքներին:
AWK հրամանը գալիս է Յունիքսի վաղ օրերից: Այն POSIX ստանդարտի մի մասն է և պետք է հասանելի լինի Unix-ի նման ցանկացած համակարգում: Եւ դրանից դուրս.
Թեև երբեմն վարկաբեկվում է իր տարիքի կամ առանձնահատկությունների բացակայության պատճառով՝ համեմատած Perl-ի նման բազմաֆունկցիոնալ լեզվի հետ, AWK-ն մնում է գործիք, որը ես սիրում եմ օգտագործել իմ ամենօրյա աշխատանքում: Երբեմն համեմատաբար բարդ ծրագրեր գրելու համար, բայց նաև հզոր մեկ տողերի պատճառով կարող եք գրել ձեր տվյալների ֆայլերի հետ կապված խնդիրները լուծելու համար:
Այսպիսով, հենց սա է այս հոդվածի նպատակը: Ցույց տալով ձեզ, թե ինչպես կարող եք օգտագործել AWK հզորությունը 80 նիշից պակաս՝ օգտակար առաջադրանքներ կատարելու համար: Այս հոդվածը նախատեսված չէ որպես ամբողջական AWK ձեռնարկ, բայց ես դեռ սկզբում ներառել եմ մի քանի հիմնական հրամաններ, այնպես որ, նույնիսկ եթե նախկինում քիչ փորձ չունեք, կարող եք տիրանալ AWK-ի հիմնական հասկացություններին:
Իմ նմուշային ֆայլերը այս AWK ձեռնարկի համար
Այդ հոդվածում նկարագրված բոլոր մեկ գծերը կփորձարկվեն նույն տվյալների ֆայլում.
cat file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Դուք կարող եք ստանալ այդ ֆայլի պատճենը առցանց՝ GitHub-ում:
Իմացեք նախապես սահմանված և ավտոմատ փոփոխականները AWK-ում
AWK-ն աջակցում է մի քանի նախապես սահմանված և ավտոմատ փոփոխականների, որոնք կօգնեն ձեզ գրել ձեր ծրագրերը: Նրանց թվում դուք հաճախ կհանդիպեք.
RS –Գրառումների բաժանարար: AWK-ն մշակում է ձեր տվյալները մեկ ձայնագրություն: Գրառումների բաժանարարը սահմանազատիչն է, որն օգտագործվում է մուտքային տվյալների հոսքը գրառումների բաժանելու համար: Լռելյայնորեն սա նոր տողի նիշն է: Այսպիսով, եթե դուք չեք փոխում այն, ապա գրառումը մուտքագրված ֆայլի մեկ տող է:
NR – Ներկայիս մուտքագրման գրառման համարը: Եթե դուք օգտագործում եք ստանդարտ նոր տողերի սահմանազատիչը ձեր գրառումների համար, ապա այն համընկնում է ընթացիկ մուտքագրման գծի համարի հետ:
FS/OFS –Նիշերը (նիշերը), որոնք օգտագործվում են որպես դաշտի բաժանարար: Երբ AWK-ն կարդում է գրառումը, այն բաժանում է տարբեր դաշտերի՝ հիմնվելով FS
արժեքը: Երբ AWK-ն ելքի վրա գրառում է տպում, այն նորից կմիանա դաշտերին, բայց այս անգամ՝ FS
բաժանիչի փոխարեն օգտագործելով OFS
բաժանիչը: Սովորաբար, FS
և OFS
նույնն են, բայց դա պարտադիր չէ: «սպիտակ տարածությունը» երկուսի համար էլ լռելյայն արժեքն է:
NF – ընթացիկ գրառման դաշտերի քանակը: Եթե դուք օգտագործում եք ստանդարտ «սպիտակ տարածության» սահմանազատիչը ձեր դաշտերի համար, ապա այն կհամընկնի ընթացիկ գրառման բառերի քանակի հետ:
Կան այլ քիչ թե շատ ստանդարտ AWK փոփոխականներ, ուստի արժե ստուգել ձեր կոնկրետ AWK իրականացման ձեռնարկը ավելի շատ մանրամասների համար: Սակայն այս ենթաբազմությունն արդեն բավական է հետաքրքիր միակողմանիներ գրել սկսելու համար։
A. AWK հրամանի հիմնական օգտագործումը
1. Տպել բոլոր տողերը
Այս օրինակը հիմնականում անօգուտ է, բայց այն, այնուամենայնիվ, լավ ներածություն կլինի AWK շարահյուսության համար.
awk '1 { print }' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
AWK ծրագրերը կազմված են մեկ կամ մի քանի pattern { action }
հայտարարություններից:
Եթե մուտքագրված ֆայլի տվյալ գրառման («տող») համար, օրինաչափությունը գնահատվում է ոչ -զրոյական արժեք (AWK-ում «true»-ին համարժեք), համապատասխան գործողությունների բլոկի հրամանները կատարվում են: Վերոնշյալ օրինակում, քանի որ 1
-ը ոչ զրոյական հաստատուն է, յուրաքանչյուր մուտքագրման համար կատարվում է { print }
գործողության բլոկը:
Մեկ այլ հնարք է { տպել }
-ը լռելյայն գործողության բլոկն է, որը կօգտագործվի AWK-ի կողմից, եթե դուք բացահայտորեն չնշեք մեկը: Այսպիսով, վերը նշված հրամանը կարող է կրճատվել հետևյալ կերպ.
awk 1 file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Գրեթե նույնքան անօգուտ, հետևյալ AWK ծրագիրը կսպառի իր մուտքը, բայց ոչինչ չի արտադրի ելքի համար.
awk 0 ֆայլ
2. Հեռացրեք ֆայլի վերնագիրը
awk 'NR>1' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Հիշեք, որ սա համարժեք է բացահայտ գրելու.
awk 'NR>1 { print }' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Այս մեկ տողում գրելու են մուտքային ֆայլի գրառումները, բացառությամբ առաջինի, քանի որ այդ դեպքում պայմանը 1>1
է, որն ակնհայտորեն ճիշտ չէ:
Քանի որ այս ծրագիրն օգտագործում է RS
-ի լռելյայն արժեքները, գործնականում այն կհեռացնի մուտքագրված ֆայլի առաջին տողը:
3. Տպել տողերը տիրույթում
Սա ընդամենը նախորդ օրինակի ընդհանրացումն է, և այն արժանի չէ բազմաթիվ բացատրությունների, բացի նրանից, որ &&
տրամաբանական and
օպերատորն է.
awk 'NR>1 && NR < 4' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
4. Հեռացնելով միայն բացատ գծերը
awk 'NF' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
AWK-ն յուրաքանչյուր գրառումը բաժանում է դաշտերի՝ հիմնվելով FS
փոփոխականում նշված դաշտերի բաժանարարի վրա: Դաշտի լռելյայն բաժանիչն է մեկ կամ մի քանի-սպիտակ տարածության նիշերը (այսինքն՝ բացատներ կամ ներդիրներ): Այդ կարգավորումների դեպքում ցանկացած գրառում, որը պարունակում է առնվազն մեկ առանց բացատ նիշ, կպարունակի առնվազն մեկ դաշտ:
Այլ կերպ ասած, միակ դեպքը, երբ NF
-ը 0 է (“false”), երբ գրառումը պարունակում է միայն բացատներ: Այսպիսով, այդ մեկ տողերը կտպեն միայն առնվազն մեկ ոչ բացատ նիշ պարունակող գրառումներ:
5. Հեռացնելով բոլոր դատարկ տողերը
awk '1' RS='' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Այս մեկ գիծը հիմնված է անհասկանալի POSIX կանոնի վրա, որը սահմանում է, եթե RS
-ը դրված է դատարկ տողի վրա, «ապա գրառումները բաժանվում են հաջորդականությամբ, որը բաղկացած է <newline> գումարածից: մեկ կամ մի քանի դատարկ տող: «
Արժե նշել POSIX տերմինաբանության մեջ, դատարկ տողը լրիվ դատարկ տող է: Միայն բացատ պարունակող տողերը չեն համարվում «դատարկ»:
6. Դաշտերի արդյունահանում
Սա, հավանաբար, AWK-ի օգտագործման ամենատարածված դեպքերից մեկն է՝ տվյալների ֆայլի որոշ սյունակներ հանելը:
awk '{ print $1, $3}' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
,
,
17,abhishek
Այստեղ ես հստակորեն դրել եմ և՛ մուտքային, և՛ ելքային դաշտերի բաժանիչները կոմայի մեջ: Երբ AWK-ն գրառումը բաժանում է դաշտերի, այն պահում է առաջին դաշտի բովանդակությունը $1-ի, երկրորդ դաշտի բովանդակությունը՝ $2-ի և այլն: Ես դա չեմ օգտագործում այստեղ, բայց արժե նշել, որ $0-ը ամբողջ ռեկորդն է:
Այս մեկ տողում դուք կարող եք նկատել, որ ես օգտագործում եմ գործողությունների բլոկ առանց նախշի: Այդ դեպքում օրինաչափության համար ենթադրվում է 1 («ճշմարիտ»), ուստի գործողությունների բլոկը կատարվում է յուրաքանչյուր գրառման համար:
Կախված ձեր կարիքներից, այն կարող է չարտադրել այն, ինչ մենք կցանկանայինք դատարկ կամ միայն բացատ գծերի համար: Այդ դեպքում այդ երկրորդ տարբերակը կարող է մի փոքր ավելի լավ լինել.
awk 'NF { print $1, $3 }' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
17,abhishek
Երկու դեպքում էլ ես հրամանի տողում փոխանցեցի FS
և OFS
հատուկ արժեքները: Մեկ այլ տարբերակ կլինի օգտագործել հատուկ BEGIN
բլոկը AWK ծրագրի ներսում՝ այդ փոփոխականները սկզբնավորելու համար, նախքան առաջին գրառումը կարդալը: Այսպիսով, կախված ձեր ճաշակից, դուք կարող եք նախընտրել դրա փոխարեն գրել հետևյալը.
awk 'BEGIN { FS=OFS="," } NF { print $1, $3 }' file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
17,abhishek
Այստեղ հարկ է նշել, որ դուք կարող եք նաև օգտագործել END
բլոկները՝ վերջին գրառումը կարդալուց հետո որոշ առաջադրանքներ կատարելու համար: Ինչպես մենք դա կտեսնենք հենց հիմա: Այսպես ասած, ես ընդունում եմ, որ դա հեռու է կատարյալ լինելուց, քանի որ միայն բացատով տողերը նրբագեղ չեն մշակվում: Մենք շուտով կտեսնենք հնարավոր լուծումը, բայց մինչ այդ եկեք որոշ մաթեմատիկական անենք…
7. Հաշվարկների կատարումը սյունակով
AWK-ն աջակցում է ստանդարտ թվաբանական օպերատորներին: Եվ ավտոմատ կերպով կփոխակերպի արժեքները տեքստի և թվերի միջև՝ կախված համատեքստից: Բացի այդ, դուք կարող եք օգտագործել ձեր սեփական փոփոխականները միջանկյալ արժեքները պահելու համար: Այն ամենը, ինչ թույլ է տալիս գրել կոմպակտ ծրագրեր տվյալների սյունակների վրա հաշվարկներ կատարելու համար.
awk '{ SUM=SUM+$1 } END { print SUM }' FS=, OFS=, file
263
Կամ, համարժեքորեն օգտագործելով +=
սղագրության շարահյուսությունը.
awk '{ SUM+=$1 } END { print SUM }' FS=, OFS=, file
263
Խնդրում ենք նկատի ունենալ, որ AWK փոփոխականները օգտագործելուց առաջ պետք չէ հայտարարագրել: Ենթադրվում է, որ չսահմանված փոփոխականը պահում է դատարկ տողը: Որը, ըստ AWK տեսակի փոխակերպման կանոնների, հավասար է 0 թվին։ Այդ հատկանիշի պատճառով ես չանհանգստացա բացահայտորեն վարվել այն դեպքի հետ, երբ $1
պարունակում է տեքստ (վերնագրում), բացատ կամ պարզապես ոչինչ: Այդ բոլոր դեպքերում այն կհաշվի որպես 0 և չի խանգարի մեր գումարմանը։ Իհարկե, այլ կլիներ, եթե փոխարենը բազմապատկումներ անեի։ Այսպիսով, ինչո՞ւ չեք օգտագործում մեկնաբանությունների բաժինը՝ այդ դեպքի համար լուծում առաջարկելու համար:
8. Ոչ դատարկ տողերի քանակի հաշվում
Ես նախկինում արդեն նշել եմ END
կանոնը։ Ահա ևս մեկ հնարավոր ծրագիր՝ ֆայլում ոչ դատարկ տողերի քանակը հաշվելու համար.
awk '/./ { COUNT+=1 } END { print COUNT }' file
9
Այստեղ ես օգտագործեցի COUNT
փոփոխականը և ավելացրի այն (+=1
) /./
կանոնավոր արտահայտությանը համապատասխանող յուրաքանչյուր տողի համար: Դա այն է, որ յուրաքանչյուր տող պարունակում է առնվազն մեկ նիշ: Վերջապես, END բլոկը օգտագործվում է վերջնական արդյունքը ցուցադրելու համար, երբ ամբողջ ֆայլը մշակվի: COUNT
անվան մեջ առանձնահատուկ բան չկա: Ես կարող էի օգտագործել Count
, count
, n
, xxxx
կամ որևէ այլ անուն, որը համապատասխանում է AWK փոփոխականի անվանման կանոններին:
Այնուամենայնիվ, արդյոք այս արդյունքը ճի՞շտ է: Դե, դա կախված է «դատարկ» տողի ձեր սահմանումից: Եթե կարծում եք, որ միայն դատարկ տողերը (ըստ POSIX-ի) դատարկ են, ապա դա ճիշտ է: Բայց միգուցե կնախընտրեի՞ք դատարկ համարել միայն բացատով տողերը:
awk 'NF { COUNT+=1 } END { print COUNT }' file
8
Այս անգամ արդյունքը տարբերվում է, քանի որ այդ ավելի ուշ տարբերակը նույնպես անտեսում է միայն բացատ տողերը, մինչդեռ սկզբնական տարբերակը անտեսում էր միայն դատարկ տողերը: Կարող եք տեսնել տարբերությունը: Ես քեզ թույլ եմ տվել դա ինքնուրույն պարզել: Մի հապաղեք օգտագործել մեկնաբանությունների բաժինը, եթե դա բավականաչափ պարզ չէ:
Ի վերջո, եթե ձեզ հետաքրքրում են միայն տվյալների տողերը, և հաշվի առնելով իմ մուտքագրված տվյալների ֆայլը, փոխարենը կարող եմ գրել.
awk '+$1 { COUNT+=1 } END { print COUNT }' file
7
Այն աշխատում է AWK տեսակի փոխակերպման կանոնների պատճառով: Ունի գումարած օրինաչափությունը ստիպում է գնահատել $1-ը թվային համատեքստում: Իմ ֆայլում տվյալների գրառումները պարունակում են թիվ իրենց առաջին դաշտում: Ոչ տվյալների գրառումները (վերնագիր, դատարկ տողեր, միայն բացատներով տողեր) պարունակում են տեքստ կամ ոչինչ: Դրանք բոլորը հավասար են 0-ի, երբ վերածվում են թվերի:
Նկատի ունեցեք, որ այս վերջին լուծումով, ի վերջո 0 միավոր ունեցող օգտատիրոջ ռեկորդը նույնպես կչեղարկվի:
B. Օգտագործելով զանգվածներ AWK-ում
Զանգվածները AWK-ի հզոր հատկանիշն են: AWK-ի բոլոր զանգվածները ասոցիատիվ զանգվածներ են, ուստի թույլ են տալիս կամայական տողը կապել մեկ այլ արժեքի հետ։ Եթե դուք ծանոթ եք ծրագրավորման այլ լեզուներին, ապա դրանք կարող եք իմանալ որպես հեշ, ասոցիատիվ աղյուսակներ, բառարաններ կամ քարտեզներ:
9. AWK զանգվածի պարզ օրինակ
Եկեք պատկերացնենք, որ ես ուզում եմ իմանալ բոլոր օգտագործողների ընդհանուր վարկը: Ես կարող եմ յուրաքանչյուր օգտվողի համար գրառում պահել ասոցիատիվ զանգվածում, և ամեն անգամ, երբ հանդիպում եմ այդ օգտվողի համար գրառում, ես ավելացնում եմ զանգվածում պահվող համապատասխան արժեքը:
awk '+$1 { CREDITS[$3]+=$1 }
END { for (NAME in CREDITS) print NAME, CREDITS[NAME] }' FS=, file
abhishek 17
sonia 129
öle 8
sylvain 109
Ես ընդունում եմ, որ սա այլևս միակողմանի չէ: Հիմնականում for
հանգույցի պատճառով, որն օգտագործվում է ֆայլի մշակումից հետո զանգվածի բովանդակությունը ցուցադրելու համար: Այսպիսով, եկեք վերադառնանք հիմա ավելի կարճ օրինակներին.
10. AWK-ի միջոցով կրկնվող տողերի նույնականացում
Զանգվածները, ինչպես մյուս AWK փոփոխականները, կարող են օգտագործվել ինչպես գործողությունների բլոկներում, այնպես էլ օրինաչափություններում: Օգտվելով դրանից՝ մենք կարող ենք գրել մեկ տող՝ միայն կրկնօրինակ տողեր տպելու համար.
awk 'a[$0]++' file
52,01 dec 2018,sonia,team
++
օպերատորը C լեզուների ընտանիքից ժառանգված հետաճող օպերատորն է (որի AWK-ն հպարտ անդամ է, շնորհիվ Բրայան Քերնիգանի, որը նրա սկզբնական հեղինակներից մեկն էր):
Քանի որ նրա անունը ենթադրում է, որ հետաճող օպերատորը ավելացնում է («ավելացնել 1») փոփոխականը, բայց միայն այն բանից հետո, երբ դրա արժեքը վերցված է ընդգրկող արտահայտության գնահատման համար:
Այդ դեպքում a[$0]
-ը գնահատվում է՝ տեսնելու, թե արդյոք գրառումը կտպվի՞, թե՞ ոչ, և երբ որոշումը կայացվել է, բոլոր դեպքերում զանգվածի մուտքն ավելանում է։
Այսպիսով, առաջին անգամ, երբ գրառումը կարդացվում է, a[$0]
-ն անորոշ է և, հետևաբար, AWK-ի համար զրոյի համարժեք է: Այսպիսով, այդ առաջին գրառումը գրված չէ ելքի վրա: Այնուհետև այդ գրառումը զրոյից փոխվում է մեկին:
Երկրորդ անգամ, երբ նույն մուտքային գրառումն ընթերցվում է, a[$0]
այժմ 1 է: Դա «ճիշտ է»: Տողը կտպվի։ Սակայն մինչ այդ զանգվածի մուտքը թարմացվում է 1-ից 2-ի: Եվ այսպես շարունակ:
11. Կրկնվող տողերի հեռացում
Որպես նախորդ մեկ տողերի հետևանք, մենք կարող ենք հեռացնել կրկնօրինակ տողերը.
awk '!a[$0]++' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Միակ տարբերությունը տրամաբանական, ոչ թե օպերատորի (!
) օգտագործումն է, որը հակադարձում է արտահայտության ճշմարտության արժեքը: Այն, ինչ կեղծ էր, դառնում է ճշմարիտ, իսկ այն, ինչ ճշմարիտ էր, դառնում է կեղծ: Տրամաբանականը բացարձակապես չի ազդում ++
գրառման ավելացման վրա, որն աշխատում է ճիշտ այնպես, ինչպես նախկինում:
Գ. Դաշտային և ռեկորդային բաժանարար մոգություն
12. Դաշտի բաժանարարների փոփոխություն
awk '$1=$1' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
Այդ ծրագիրը սահմանում է FS
և OFS
փոփոխականները՝ կոմայի մեջ որպես մուտքային դաշտի բաժանարար և ստորակետը որպես ելքային դաշտի բաժանարար օգտագործելու համար։ Քանի որ AWK-ն չի փոխում ելքային ռեկորդը, քանի դեռ դուք չեք փոխել դաշտը, $1=$1
հնարքն օգտագործվում է AWK-ին ստիպելու կոտրել ռեկորդը և այն նորից հավաքել՝ օգտագործելով ելքային դաշտի բաժանիչը:
Հիշեք այստեղ կանխադրված գործողությունների բլոկը { print }
է: Այսպիսով, դուք կարող եք վերաշարադրել դա ավելի հստակ որպես.
awk '$1=$1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
Դուք կարող եք նկատել, որ երկու օրինակները նույնպես վերացնում են դատարկ տողերը: Ինչո՞ւ։ Դե, հիշեք AWK-ի փոխակերպման կանոնները. դատարկ տողը «կեղծ է: «Մյուս բոլոր տողերը «ճշմարիտ են. $1=$1
արտահայտությունը ազդեցություն է, որը փոխում է $1
-ը: Այնուամենայնիվ, սա նույնպես արտահայտություն է. Եվ այն գնահատվում է $1
արժեքով, որը դատարկ տողի համար «false» է: Եթե դուք իսկապես ցանկանում եք բոլոր տողերը, փոխարենը ձեզ հարկավոր է գրել նման բան.
awk '($1=$1) || 1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
Հիշու՞մ եք &&
օպերատորը: Դա տրամաբանական ԵՎ էր։ ||
-ը տրամաբանական ԿԱՄ է: Փակագծերն այստեղ անհրաժեշտ են օպերատորների գերակայության կանոնների պատճառով: Առանց դրանց օրինակը սխալմամբ կմեկնաբանվեր որպես $1=($1 || 1)
: Որպես վարժություն, ես թույլ տվեցի ձեզ ստուգել, թե ինչպես արդյունքն այն ժամանակ տարբեր կլիներ:
Ի վերջո, եթե դուք այնքան էլ հետաքրքրված չեք թվաբանությամբ, գրազ եմ գալիս, որ կնախընտրեք ավելի պարզ լուծում.
awk '{ $1=$1; print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
13. Բազմաթիվ բացատների հեռացում
awk '$1=$1' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Սա գրեթե նույն ծրագիրն է, ինչ նախորդը։ Այնուամենայնիվ, ես թողեցի դաշտերի բաժանիչները իրենց լռելյայն արժեքներին: Այսպիսով, մի քանի բացատներ օգտագործվում են որպես մուտքային դաշտի բաժանարար, բայց միայն մեկ տարածություն օգտագործվում է որպես ելքային դաշտի բաժանարար: Սա ունի բազմակի բացատների միավորումը մեկ տարածության մեջ:
14. Տողերի միացում AWK-ի միջոցով
Մենք արդեն օգտագործել ենք OFS
՝ ելքային դաշտի բաժանիչը: Ինչպես կարող էիք կռահել, այն ունի ORS
նմանակը, որը սահմանում է ելքային գրառումների բաժանիչը.
awk '{ print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek
Այստեղ ես օգտագործեցի բացատ յուրաքանչյուր գրառումից հետո նոր տող նիշի փոխարեն: Այս մեկ երեսպատումը բավարար է որոշ օգտագործման դեպքերում, բայց այն դեռևս ունի որոշ թերություններ:
Առավել ակնհայտ է, որ այն չի ջնջում միայն բացատ գծերը (öle-ից հետո լրացուցիչ բացատները դրանից են բխում): Այսպիսով, ես կարող եմ փոխարենը օգտագործել սովորական սովորական արտահայտություն.
awk '/[^[:space:]]/ { print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek
Հիմա ավելի լավ է, բայց դեռ հնարավոր խնդիր կա։ Ավելի ակնհայտ կլինի, եթե բաժանարարը փոխենք տեսանելի բանի.
awk '/[^[:space:]]/ { print $3 }' FS=, ORS='+' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek+
Տողի վերջում կա հավելյալ բաժանիչ, քանի որ դաշտի բաժանարարը գրված է յուրաքանչյուր գրառումից հետո: Այդ թվում՝ վերջինը։
Դա շտկելու համար ես կվերագրեմ ծրագիրը, որպեսզի ցուցադրվի հատուկ տարանջատիչ նախքան գրառումը` սկսած երկրորդ ելքային գրառումից:
awk '/[^[:space:]]/ { print SEP $3; SEP="+" }' FS=, ORS='' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek
Քանի որ ես ինքս եմ հոգում տարանջատիչն ավելացնելու մասին, ես նաև դրեցի ստանդարտ AWK ելքային ռեկորդների բաժանիչը դատարկ տողի վրա: Այնուամենայնիվ, երբ դուք սկսում եք գործ ունենալ բաժանարարների կամ ձևաչափման հետ, դա կարող է նշան լինել, որ դուք պետք է մտածեք print
դրույթի փոխարեն օգտագործել printf ֆունկցիան: Ինչպես կտեսնենք հենց հիմա:
Դ. Դաշտի ձևավորում
Ես արդեն նշել եմ AWK և C ծրագրավորման լեզուների փոխհարաբերությունները։ Ի թիվս այլ բաների, C լեզվի ստանդարտ գրադարանից AWK-ն ժառանգում է հզոր printf
ֆունկցիան, որը թույլ է տալիս մեծ վերահսկել ելք ուղարկվող տեքստի ձևաչափումը:
printf
ֆունկցիան ընդունում է ձևաչափ` որպես առաջին արգումենտ, որը պարունակում է ինչպես պարզ տեքստ, որը բառացիորեն կարտադրվի, այնպես էլ տեքստային նշաններ, որոնք օգտագործվում են ելքի տարբեր հատվածների ձևաչափման համար: Վառանիշները նույնականացվում են %
նիշով: Ամենատարածվածներն են %s
(լարերի ձևաչափման համար), %d
(ամբողջ թվերի ձևաչափման համար) և %f
(լողացող կետով թվերի ձևաչափման համար): ) Քանի որ սա կարող է բավականին վերացական լինել, եկեք տեսնենք մի օրինակ.
awk '+$1 { printf("%s ", $3) }' FS=, file; echo
sylvain sonia sonia sonia sylvain öle abhishek
Դուք կարող եք նկատել, քանի որ print
հայտարարության հակառակը, printf
ֆունկցիան չի օգտագործում OFS
և ORS
-ը: արժեքներ։ Այսպիսով, եթե ցանկանում եք ինչ-որ տարանջատիչ, դուք պետք է բացահայտորեն նշեք դա, ինչպես ես արեցի՝ ավելացնելով բացատ նիշ ֆորմատի տողի վերջում: Սա այն գինն է, որը պետք է վճարել արտադրանքի ամբողջական վերահսկողության համար:
Թեև ամենևին էլ ձևաչափի ցուցիչ չէ, սա հիանալի առիթ է ներկայացնելու \n
նշումը, որը կարող է օգտագործվել ցանկացած AWK տողի մեջ՝ նոր տողի նիշը ներկայացնելու համար:
awk '+$1 { printf("%s\n", $3) }' FS=, file
sylvain
sonia
sonia
sonia
sylvain
öle
abhishek
15. Աղյուսակային արդյունքների պատրաստում
AWK-ն պարտադրում է գրառումների/դաշտի տվյալների ձևաչափը՝ հիմնված սահմանազատողների վրա: Այնուամենայնիվ, օգտագործելով printf
ֆունկցիան, կարող եք նաև արտադրել ֆիքսված լայնության աղյուսակային ելք: Քանի որ printf
հայտարարության յուրաքանչյուր ձևաչափի ցուցիչ կարող է ընդունել լայնության կամընտիր պարամետր.
awk '+$1 { printf("%10s | %4d\n", $3, $1) }' FS=, file
sylvain | 99
sonia | 52
sonia | 52
sonia | 25
sylvain | 10
öle | 8
abhishek | 17
Ինչպես տեսնում եք, յուրաքանչյուր դաշտի լայնությունը նշելով, AWK-ն դրանք փակում է դեպի ձախ՝ բացատներով: Տեքստի համար սովորաբար նախընտրելի է ներդիր աջ կողմում, ինչին կարելի է հասնել՝ օգտագործելով բացասական լայնության թիվը: Բացի այդ, ամբողջ թվերի համար մենք կարող ենք ցանկանալ դաշտերը բացատների փոխարեն զրոներով լրացնել: Սա կարելի է ստանալ՝ օգտագործելով բացահայտ 0 դաշտի լայնությունից առաջ.
awk '+$1 { printf("%-10s | %04d\n", $3, $1) }' FS=, file
sylvain | 0099
sonia | 0052
sonia | 0052
sonia | 0025
sylvain | 0010
öle | 0008
abhishek | 0017
16. Լողացող միավոր թվերի հետ գործ ունենալը
%f
ձևաչափը շատ բացատրությունների արժանի չէ…
awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%f",SUM/NUM); }' FS=, file
AVG=37.571429
… բացառությամբ, եթե ասենք, որ դուք գրեթե միշտ ցանկանում եք հստակորեն սահմանել դաշտի լայնությունը և ցուցադրվող արդյունքի ճշգրտությունը.
awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%6.1f",SUM/NUM); }' FS=, file
AVG= 37.6
Այստեղ դաշտի լայնությունը 6 է, ինչը նշանակում է, որ դաշտը կզբաղեցնի 6 նիշի տարածություն (ներառյալ կետը և ի վերջո լրացված է ձախ կողմում բացատներով, ինչպես սովորաբար): .1 ճշգրտությունը նշանակում է, որ մենք ուզում ենք թիվը ցույց տալ 1 տասնորդական թվերով կետից հետո: Ես թույլ եմ տալիս գուշակել, թե ինչ է ցուցադրելու %06.1
փոխարեն:
E. AWK-ում լարային ֆունկցիաների օգտագործումը
Բացի printf
ֆունկցիայից, AWK-ն պարունակում է մի քանի այլ գեղեցիկ լարերի մանիպուլյացիայի գործառույթներ: Այդ տիրույթում, Gawk-ի նման ժամանակակից ներդրումներն ունեն ավելի հարուստ ներքին գործառույթներ՝ ավելի ցածր շարժունակության գնով: Ինչ վերաբերում է ինքս ինձ, ես այստեղ կմնամ ընդամենը մի քանի POSIX-ով սահմանված գործառույթով, որոնք պետք է նույնը աշխատեն ցանկացած վայրում:
17. Տեքստի վերածում մեծատառի
Սա, ես շատ եմ օգտագործում, քանի որ այն լավ է լուծում միջազգայնացման խնդիրները.
awk '$3 { print toupper($0); }' file
99,01 JUN 2018,SYLVAIN,TEAM:::ADMIN
52,01 DEC 2018,SONIA,TEAM
52,01 DEC 2018,SONIA,TEAM
25,01 JAN 2019,SONIA,TEAM
10,01 JAN 2019,SYLVAIN,TEAM:::ADMIN
8,12 JUN 2018,ÖLE,TEAM:SUPPORT
17,05 APR 2019,ABHISHEK,GUEST
Փաստորեն, սա թերևս ամենալավ և դյուրակիր լուծումն է տեքստը կեղևից մեծատառի վերածելու համար:
18. Լարի մասի փոփոխություն
Օգտագործելով substr
հրամանը, դուք կարող եք բաժանել նիշերի տողը որոշակի երկարությամբ: Այստեղ ես օգտագործում եմ այն երրորդ դաշտի միայն առաջին նիշը մեծատառացնելու համար.
awk '{ $3 = toupper(substr($3,1,1)) substr($3,2) } $3' FS=, OFS=, file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,Sylvain,team:::admin
52,01 dec 2018,Sonia,team
52,01 dec 2018,Sonia,team
25,01 jan 2019,Sonia,team
10,01 jan 2019,Sylvain,team:::admin
8,12 jun 2018,Öle,team:support
17,05 apr 2019,Abhishek,guest
substr
ֆունկցիան վերցնում է սկզբնական տողը, առաջին հանվող նիշի (1-ի վրա հիմնված) ինդեքսը և հանվող նիշերի քանակը։ Եթե վերջին արգումենտը բացակայում է, substr
վերցնում է տողի մնացած բոլոր նիշերը:
Այսպիսով, substr($3,1,1)
կգնահատվի $3
-ի առաջին նիշին, իսկ substr($3,2)
մնացածին նրանք.
19. Դաշտերի բաժանում ենթադաշտերում
AWK ռեկորդային դաշտի տվյալների մոդելն իսկապես գեղեցիկ է: Այնուամենայնիվ, երբեմն դուք ցանկանում եք դաշտերն իրենք բաժանել մի քանի մասի, հիմնվելով որոշ ներքին բաժանարարի վրա.
awk '+$1 { split($2, DATE, " "); print $1,$3, DATE[2], DATE[3] }' FS=, OFS=, file
99,sylvain,jun,2018
52,sonia,dec,2018
52,sonia,dec,2018
25,sonia,jan,2019
10,sylvain,jan,2019
8,öle,jun,2018
17,abhishek,apr,2019
Զարմանալիորեն, սա աշխատում է նույնիսկ եթե իմ որոշ դաշտեր բաժանված են մեկից ավելի բացատներով: Հիմնականում պատմական պատճառներով, երբ բաժանարարը մեկ տարածություն է, split
-ը հաշվի կառնի «տարրերն առանձնացված են բացատներով: Եվ ոչ միայն մեկով. FS
հատուկ փոփոխականը հետևում է նույն պայմանին:
Այնուամենայնիվ, ընդհանուր դեպքում մեկ նիշերի տողը համապատասխանում է մեկ նիշի: Այսպիսով, եթե ձեզ ավելի բարդ բան է պետք, դուք պետք է հիշեք, որ դաշտի բաժանարարը ընդլայնված կանոնավոր արտահայտություն է:
Որպես օրինակ, եկեք տեսնենք, թե ինչպես է վարվելու խմբային դաշտը, որը կարծես բազմարժեք դաշտ է, օգտագործելով երկու կետ որպես բաժանարար.
awk '+$1 { split($4, GRP, ":"); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team
sonia team
sonia team
sonia team
sylvain team
öle team support
abhishek guest
Մինչդեռ ես ակնկալում էի, որ յուրաքանչյուր օգտագործողի համար կցուցադրվի մինչև երկու խումբ, այն ցույց է տալիս միայն մեկը նրանցից շատերի համար: Այդ խնդիրն առաջանում է տարանջատողի բազմաթիվ երևույթներից: Այսպիսով, լուծումը հետևյալն է.
awk '+$1 { split($4, GRP, /:+/); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team admin
sonia team
sonia team
sonia team
sylvain team admin
öle team support
abhishek guest
Չակերտների փոխարեն շեղերը նշանակում են բառացի որպես կանոնավոր արտահայտություն, այլ ոչ թե պարզ տող, իսկ գումարած նշանը ցույց է տալիս, որ այս արտահայտությունը կհամապատասխանի նախորդ նիշի մեկ կամ մի քանի երևույթներին: Այսպիսով, այդ դեպքում յուրաքանչյուր բաժանարար կազմված է (ամենաերկար հաջորդականությունից) մեկ կամ մի քանի հաջորդական երկու կետ:
20. Որոնում և փոխարինում AWK հրամաններով
Խոսելով կանոնավոր արտահայտությունների մասին, երբեմն ուզում եք փոխարինում կատարել sed s///g
հրամանի նման, բայց միայն մեկ դաշտում: gsub
հրամանն այն է, ինչ ձեզ անհրաժեշտ է այդ դեպքում.
awk '+$1 { gsub(/ +/, "-", $2); print }' FS=, file
99 01-jun-2018 sylvain team:::admin
52 01-dec-2018 sonia team
52 01-dec-2018 sonia team
25 01-jan-2019 sonia team
10 01-jan-2019 sylvain team:::admin
8 12-jun-2018 öle team:support
17 05-apr-2019 abhishek guest
gsub
ֆունկցիան փնտրում է կանոնավոր արտահայտություն, փոխարինող տող և փոփոխվող տեքստ պարունակող փոփոխական: Եթե դա ավելի ուշ բացակայում է, ապա ենթադրվում է $0:
F. AWK-ում արտաքին հրամանների հետ աշխատելը
AWK-ի մեկ այլ հիանալի առանձնահատկությունն այն է, որ դուք հեշտությամբ կարող եք կանչել արտաքին հրամաններ՝ ձեր տվյալները մշակելու համար: Հիմնականում դա անելու երկու եղանակ կա՝ օգտագործելով system
հրահանգը՝ ծրագիր կանչելու համար և թույլ տալով, որ այն խառնի իր արդյունքը AWK ելքային հոսքում: Կամ օգտագործելով խողովակ, որպեսզի AWK-ն կարողանա գրավել արտաքին ծրագրի ելքը՝ արդյունքն ավելի լավ վերահսկելու համար:
Դրանք կարող են ինքնին հսկայական թեմաներ լինել, բայց այստեղ կան մի քանի պարզ օրինակներ, որոնք ցույց կտան ձեզ այդ հատկանիշների հիմքում ընկած ուժը:
21. Ֆայլի վերևում ամսաթիվ ավելացնելը
awk 'BEGIN { printf("UPDATED: "); system("date") } /^UPDATED:/ { next } 1' file
UPDATED: Thu Feb 15 00:31:03 CET 2018
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Այդ AWK ծրագրում ես սկսում եմ ԹԱՐՄԱՑՎԱԾ աշխատանքը ցուցադրելով։ Այնուհետև ծրագիրը կանչում է արտաքին ամսաթիվ հրամանը, որն իր արդյունքը կուղարկի արդյունքի վրա հենց այդ փուլում AWK-ի կողմից արտադրված տեքստից հետո:
AWK ծրագրի մնացած մասը պարզապես հեռացրեք թարմացման հայտարարությունը, որն ի վերջո առկա է ֆայլում և տպեք բոլորը: մյուս տողերը (1
կանոնով):
Ուշադրություն դարձրեք next
հայտարարությանը: Այն օգտագործվում է ընթացիկ գրառումների մշակումը ընդհատելու համար: Սա մուտքային ֆայլից որոշ գրառումներ անտեսելու ստանդարտ միջոց է:
22. Արտաքին դաշտի ձևափոխում
Ավելի բարդ դեպքերի համար գուցե հարկ լինի հաշվի առնել |-ը getline VARIABLE
AWK բառակապակցություն.
awk '+$1 { CMD | getline $5; close(CMD); print }' CMD="uuid -v4" FS=, OFS=, file
99,01 jun 2018,sylvain,team:::admin,5e5a1bb5-8a47-48ee-b373-16dc8975f725
52,01 dec 2018,sonia,team,2b87e9b9-3e75-4888-bdb8-26a9b34facf3
52,01 dec 2018,sonia,team,a5fc22b5-5388-49be-ac7b-78063cbbe652
25,01 jan 2019,sonia,team,3abb0432-65ef-4916-9702-a6095f3fafe4
10,01 jan 2019,sylvain,team:::admin,592e9e80-b86a-4833-9e58-1fe2428aa2a2
8,12 jun 2018,öle,team:support,3290bdef-fd84-4026-a02c-46338afd4243
17,05 apr 2019,abhishek,guest,e213d756-ac7f-4228-818f-1125cba0810f
Սա կգործարկի CMD
փոփոխականում պահված հրամանը, կկարդա այդ հրամանի ելքի առաջին տողը և կպահի այն $5
փոփոխականում:
Հատուկ ուշադրություն դարձրեք փակ հայտարարությանը, որն այստեղ կարևոր է, քանի որ մենք ցանկանում ենք, որ AWK-ն ստեղծի արտաքին հրամանի նոր օրինակ ամեն անգամ, երբ այն կատարում է CMD | getline
հայտարարություն. Առանց փակ հայտարարության, AWK-ն փոխարենը կփորձեր կարդալ նույն հրամանի օրինակից ստացված մի քանի տող:
23. Դինամիկ գեներացվող հրամանների կանչում
AWK-ի հրամանները պարզապես պարզ տողեր են՝ առանց որևէ հատուկ բանի: Դա խողովակների օպերատորն է, որը խթանում է արտաքին ծրագրերի կատարումը: Այսպիսով, եթե ձեզ անհրաժեշտ է, կարող եք դինամիկ կերպով կառուցել կամայական բարդ հրամաններ՝ օգտագործելով AWK տողերի մանիպուլյացիայի գործառույթները և օպերատորները:
awk '+$1 { cmd = sprintf(FMT, $2); cmd | getline $2; close(cmd); print }' FMT='date -I -d "%s"' FS=, file
99 2018-06-01 sylvain team:::admin
52 2018-12-01 sonia team
52 2018-12-01 sonia team
25 2019-01-01 sonia team
10 2019-01-01 sylvain team:::admin
8 2018-06-12 öle team:support
17 2019-04-05 abhishek guest
Մենք արդեն հանդիպել ենք printf
ֆունկցիային: sprintf
-ը շատ նման է, բայց կվերադարձնի կառուցված տողը, այլ ոչ թե ուղարկի այն ելքային:
24. Տվյալների միացում
Որպեսզի ցույց տամ փակ հայտարարության նպատակը, ես թույլ եմ տալիս փորձել վերջին օրինակը.
awk '+$1 { CMD | getline $5; print }' CMD='od -vAn -w4 -t x /dev/urandom' FS=, file
99 01 jun 2018 sylvain team:::admin 1e2a4f52
52 01 dec 2018 sonia team c23d4b65
52 01 dec 2018 sonia team 347489e5
25 01 jan 2019 sonia team ba985e55
10 01 jan 2019 sylvain team:::admin 81e9a01c
8 12 jun 2018 öle team:support 4535ba30
17 05 apr 2019 abhishek guest 80a60ec8
Որպես վերևի uuid
հրամանի հակառակ օրինակի հակառակը, այստեղ կա միայն մեկ օրինակ od
գործարկվելիս AWK ծրագիրն աշխատում է, և յուրաքանչյուր գրառում մշակելիս մենք կարդում ենք այդ նույն գործընթացի արդյունքի ևս մեկ տող:
Եզրակացություն
AWK-ի այդ արագ շրջայցը, անշուշտ, չի կարող փոխարինել այդ գործիքի լիարժեք դասընթացին կամ ձեռնարկին: Այնուամենայնիվ, ձեզնից նրանց համար, ովքեր ծանոթ չէին դրան, հուսով եմ, որ այն ձեզ բավականաչափ գաղափարներ տվեց, որպեսզի կարողանաք անմիջապես ավելացնել AWK-ն ձեր գործիքների տուփին:
Մյուս կողմից, եթե դուք արդեն AWK-ի սիրահար էիք, կարող եք այստեղ գտնել որոշ հնարքներ, որոնք կարող եք օգտագործել ավելի արդյունավետ լինելու կամ պարզապես ձեր ընկերներին տպավորելու համար:
Այնուամենայնիվ, ես չեմ ձևացնում, որ սպառիչ եմ: Այսպիսով, բոլոր դեպքերում, մի հապաղեք կիսվել ձեր սիրած AWK մեկ երթևեկության կամ AWK-ի ցանկացած այլ խորհուրդներով՝ օգտագործելով ստորև բերված մեկնաբանությունների բաժինը: