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-ի ցանկացած այլ խորհուրդներով՝ օգտագործելով ստորև բերված մեկնաբանությունների բաժինը: