Awk search string ayon sa variable na halaga. AWK: Mga halimbawang programa. Pinagsasama-sama ang mga Filter at Print Command

Sa artikulong ito ipapakita namin sa iyo ang ilan praktikal na mga halimbawa sa kung paano gamitin ang AWK sa .

Panimula

Ang AWK ay pinangalanan sa mga pangalan ng mga may-akda nito: Alfred Aho, Peter Weinberger at Brian Kernighan. Grabe ang AWK kapaki-pakinabang na wika mga script para sa pagproseso ng teksto. Ang wikang ito ay tumatakbo sa isang interpreter. Nagbibigay-daan ito sa user na iproseso ang ilang input, tukuyin ang mga variable, gamitin mga lohikal na operator, string at numeric na mga function, kunin ang data at gumawa ng mga naka-format na ulat. Ang syntax ng AWK ay halos kapareho sa wikang C at isang direktang hinalinhan sa Perl. Ang lahat ng AWK script ay maaaring ma-convert sa Perl script gamit ang A2P utility.

Mga kinakailangan

Ang AWK interpreter ay karaniwang kasangkapan, na matatagpuan sa bawat pamamahagi ng Linux. Ang pakete ng gawk ay naglalaman ng isang open-source na bersyon ng AWK source code, at depende sa Pamamahagi ng Linux maaari itong mai-install mula sa source file o gamit ang gawk o mawk packages na kasama sa iyong partikular na pamamahagi ng Linux.

Pag-install

Sa mga karapatan ng superuser

Ssh root@IP_Address

Upang i-install ang command utility Mga string ng AWK sa /Fedora o anumang iba pa sa batay sa RPM Pamamahagi ng Linux, patakbuhin ang sumusunod na command:

Yum install gawk

Sa / , kailangan mong tawagan ang command na ito upang mai-install ang Gawk:

Apt-get install gawk

Mga Halimbawa ng AWK Command

Ang mga simpleng awk command ay madaling mapatakbo mula sa command line, at para sa mas kumplikadong mga gawain ay dapat isulat bilang awk script sa isang file. Nakalista sa ibaba ang ilan kapaki-pakinabang na mga halimbawa awk command at executable script.

Maaari mong gamitin ang AWK command upang mag-print lamang ng mga partikular na column mula sa isang input field. Halimbawa, gamit ang command sa ibaba maaari mong malaman ang listahan ng mga IP address na nakakonekta sa server:

Netstat -anp|grep tcp|awk "(print $5)"| gupitin -d: -f1 | uri | uniq -c | uri -n

Ito ay lubhang kapaki-pakinabang kung ikaw ay nag-iimbestiga kung ang iyong server ay nasa ilalim Pag-atake ng DoS o DDoS.

Sa sumusunod na halimbawa, ginagamit namin ang AWK upang maghanap ng partikular na pattern sa ilang partikular na column at gumawa ng ilang pagkilos batay sa resulta:

Exim -bpr | grep frozen | awk("print $3") | xargs exim -Mrm

Tatanggalin ng command sa itaas ang lahat ng frozen na mensahe email mula sa Exim mail queue.

Ang AWK ay kadalasang ginagamit upang gumanap ng kapaki-pakinabang at praktikal na pagproseso at pagmamanipula ng teksto. Halimbawa, maaari naming gamitin ang AWK upang alisin ang mga duplicate sa text file nang walang pag-uuri:

Awk "!x[$0]++" file-with-duplicates > new-file-without-duplicates

Ang sumusunod na command ay magpi-print ng limang random na numero mula 0 hanggang 999:

Awk "SIMULA ( para sa (i = 1; i<= 5; i++) print int(1000 * rand()) }"

Gamitin ang sumusunod na command upang mabilang ang bilang ng mga linya sa isang file na pinangalanang "sample_file":

Awk "END ( print NR )" sample_file

Ang sumusunod na command ay magpi-print ng lahat ng mga linya sa file na "sample_file" na naglalaman ng mga linya na nagsisimula sa 'A' o 'a' na sinusundan ng 're':

Awk "/re/(print)" /opt/sample_file

Maaari mong gamitin ang AWK command para sa mas kumplikadong mga operasyon. Kung medyo mabagal ang pagtakbo ng iyong website, maaari mong gamitin ang sumusunod na command upang suriin kung may ilang problema sa I/O disk (at/o network, sa ilang bihirang kaso):

Tac /proc/stat | awk "/^btime/ (up=systime()-$2;print "up " up/86400 "d"); /^cpu / (print "user " $2/up "%, maganda " $3/up "%, sys " $4/pataas "%, idle " $5/up "%, iowait " $6/up "%, magnakaw " $9/up "%\niowait/used " $6 / ($2+$3+$4) ", magnakaw/nagamit "$9 / ($2+$3+$4)"

Ang ibig sabihin ng IOWAIT ay kung gaano katagal ang mga proseso ay naharang habang abala sa I/O, pangunahin sa disk storage o marahil sa network. Ang STEAL ay nangangahulugan kung gaano katagal ang mga proseso ay hinarangan ng CPU Time slice luck sa server. Ang nabanggit sa itaas ay naghihintay para sa oras ng CPU ng gumagamit (=USER + NICE + SYSTEM) ay nagpapakita ng abalang I/O, ang nakawin sa itaas na tiningnan ay nagpapakita ng isang abalang CPU.

Ang sumusunod na script ay gumagamit ng isang simpleng awk command na naghahanap sa input file na '/etc/passwd' at nagbibigay ng output kasama ang username na sinusundan ng petsa at oras ng huling login:

Vi login-check #!/bin/bash para sa user sa `awk -F: "(print $1)" /etc/passwd` do echo -n "$user: " daliri $user | grep Huli kung [ $? != 0 ]; tapos echo fi

Gawing executable ang script:

Chmod 755 login-check

Isagawa ang script:

./login-check

Dapat mong makita ang mga user account na magagamit sa server, at pagkatapos ay ang petsa at oras ng huling pag-login ng bawat user.

Konklusyon

Mayroong ilang mga bagong wika tulad ng Perl at Python na maaaring gamitin sa halip na AWK, ngunit ang paggamit ng AWK ay may ilang mga pakinabang gaya ng:

  • Napakadaling makilala ang AWK.
  • Maaaring gamitin ang AWK upang malutas ang ilang uri ng mga problema nang mas mabilis at lumikha ng mas mahusay na mga script kaysa sa paggamit ng iba pang mga tool/wika.
  • Ang AWK ay lubhang kapaki-pakinabang kapag nagtatrabaho sa malalaking file tulad ng mga log at iba pa dahil sa tulong ng AWK command/script maaari kang lumikha ng na-filter at nababasang ulat.

Sa artikulong ito, plano kong magbahagi ng mga kapaki-pakinabang na halimbawa na makakatulong sa akin na malutas ang mga pang-araw-araw na problema at lubos na gawing simple ang paggamit ng command line. Para sa mga hindi pa pamilyar sa AWK, inirerekumenda ko na talagang master mo ang scripting language na ito; Plano kong samahan ang bawat halimbawa ng maliliit na komento na nagbibigay-liwanag sa mga nuances ng paggamit ng ilang mga operator.
.

Naghahanap kami ng isang linya na may isang parameter bind-address sa configuration file.

ugat@debian:~# awk ‘/bind-address/’ /etc/mysql/my.cnf
bind-address = 127.0.0.1
bind-address = 192.168.1.110

Mga Paliwanag: Ang AWK ay may sumusunod na syntax at mga opsyon.

awk[-f program_file | 'program'] [-Fdelimiter]
[-v variable=value] [file ...]

−F halaga - tumutukoy sa separator (nagtatakda ng halaga ng built-in na FS variable);
−f file - ang teksto ng programa ay binabasa mula sa isang file, sa halip na ang command line. Ang pagbabasa mula sa maramihang mga file ay suportado;
−v var=value - pagtatalaga ng kinakailangang halaga sa isang variable;
−− — minarkahan ang katapusan ng listahan ng mga opsyon.

Halimbawa Blg. 2

Sa halimbawa sa itaas, ang paghahanap ay ginagawa sa isang file, ngunit maaari ding tanggapin ng AWK ang output ng isa pang command. Subukan nating gawing kumplikado ang ating halimbawa nang naaayon.

ugat@debian-wordpress:~# pusa /etc/mysql/my.cnf | awk '/bind-address/'
bind-address = 127.0.0.1
bind-address = 192.168.1.110

Tulad ng nakikita mo, ang resulta ng output ay nanatiling eksaktong pareho, kahit na ang disenyo, siyempre, ay naging mas kumplikado. Dapat sabihin na sa halimbawang ito ay hindi lubos na ipinapayong gamitin ang pangalawang opsyon, dahil ito ay mas kumplikado. Subukan nating isaalang-alang ang iba pang mga sitwasyon kung saan ang paggamit ng gayong disenyo ay makatwiran.

Halimbawa Blg. 3

Maglista ng mga simbolikong link at landas upang i-target ang mga file.

ugat@debian:~# ls -l /bin/ | awk '/lrwxrwxrwx/ ( print $9, $10, $11)'
bzcmp -> bzdiff
bzegrep -> bzgrep
bzfgrep -> bzgrep
bzless -> bzmore
lessfile -> lesspipe
lsmod -> kmod
mt -> /etc/alternatives/mt
nc -> /etc/alternatives/nc
netcat -> /etc/alternatives/netcat
bukas -> openvt
pidof -> /sbin/killall5
rbash -> bash
rnano -> nano
sh -> gitling
sh.distrib -> gitling

Mga Paliwanag: ang awk program ay isang template pair ( pattern) at mga aksyon ( (aksyon)), pati na rin ang mga kahulugan ng mga function na tinukoy ng gumagamit. Ang template at aksyon ay ganito ang hitsura: pattern (aksyon) Maaaring tanggalin ang template o aksyon. Sa unang kaso, ang aksyon ay isasagawa sa bawat linya, sa pangalawa, ang normal na output sa screen ay isasagawa, katumbas ng utos(print). Ang mga keyword na ito ay hindi maaaring isama sa iba pang mga pattern.

Ang input string ay karaniwang binubuo ng mga field na pinaghihiwalay ng whitespace. (Maaaring baguhin ang default na setting na ito gamit ang built-in na variable FS o mga pagpipilian -F delimiter.) Ang mga patlang ay itinalagang $1, $2, …; Ang $0 ay tumutukoy sa buong linya.

Halimbawa Blg. 4

Batay sa impormasyon sa itaas, tingnan natin ang isang halimbawa sa pagpapalit ng default na delimiter - tingnan ang listahan ng lahat ng user nang walang karagdagang impormasyon.

ugat@debian:~# awk -F ":" '( print $1 )' /etc/passwd
ugat
demonyo
bin
sys
pag-sync
mga laro
lalaki

(Pinaikli ang output ng command)

Mga Paliwanag: dahil sa file /etc/passwd ang mga tala ay nakaimbak sa anyo " ugat:x:0:0:root:/root:/bin/bash", medyo lohikal na pumili ng colon bilang isang separator at ipakita ang pinakaunang field ( $1 ) bawat linya ( $0 ).

Halimbawa Blg. 5

Lahat sa parehong file sa mga user, mabibilang mo ang kanilang numero.

ugat@debian:~# awk 'END ( print NR )' /etc/passwd
25

Mga Paliwanag: Mga espesyal na template MAGSIMULA At WAKAS ay maaaring gamitin upang makakuha ng kontrol bago basahin ang unang linya ng input at pagkatapos basahin ang huling linya ng input, ayon sa pagkakabanggit.

Ang Awk ay karaniwang isang stream editor tulad ng sed. Maaari mong i-pipe ang text sa program na ito at maaari itong manipulahin sa bawat linya. Ang programa ay maaari ding magbasa mula sa isang file. Ang Awk ay isa ring programming language. Nangangahulugan ito na magagawa ng awk ang lahat ng kayang gawin ni sed, at marami pang iba.

Hindi tulad ng sed, naaalala ng awk ang konteksto, gumawa ng mga paghahambing, at marami pang ibang bagay na maaaring gawin ng ibang mga programming language. Halimbawa, hindi ito limitado sa isang linya. Sa wastong kasanayan, maaari itong kumonekta ng maraming linya.

Ang pinaka simpleng anyo awk ganito ang hitsura:

Awk "(some_action here)"

Ang "Some_action_here" ay maaaring isang simpleng expression upang i-print ang resulta, o isang bagay na mas kumplikado. Ang syntax ay katulad ng "C" na programming language. Simpleng halimbawa:

Awk "(print $1,$3)"

ibig sabihin ay i-print ang una at ikatlong column, kung saan ang mga column ay nangangahulugang "mga bagay na pinaghihiwalay ng puting espasyo". White space = tab o espasyo.

Live na halimbawa:

Echo "1 2 3 4" | awk "(print $1,$3)" 1 3

Ikalawang Bahagi: Ano ang Magagawa ng AWK?

Ang pangunahing layunin ng AWK sa buhay ay upang manipulahin ang input nito sa isang line-by-line na batayan. awk program karaniwang gumagana sa istilo

Kung ang gusto mong gawin ay hindi akma sa modelong ito, maaaring hindi akma ang awk para sa iyong ideya.

Ang karaniwang syntax na ginagamit sa awk programming ay maaaring ilarawan bilang mga sumusunod:

Awk sample ((mga) command)

Ibig sabihin nito

"Tingnan ang bawat linya ng input upang makita kung mayroong isang PATTERN doon. Kung nandoon, patakbuhin ang nasa pagitan ng ()"

Maaari mong laktawan ang alinman sa SAMPLE o COMMAND

Kung hindi ka tumukoy ng pattern, ilalapat ang command sa BAWAT linya.

Kung ang utos ay tinanggal, ito ay katumbas ng pagtukoy (i-print lamang ang linya):

(print)

Mga partikular na halimbawa:

Awk "/#/ (i-print ang "May komento sa linyang ito")" /etc/hosts

ay magpi-print ng "Ang linyang ito ay may komento" para sa bawat linya na naglalaman ng hindi bababa sa isang "#" saanman sa linya sa /etc/hosts

Pagbabago para sa kalinawan

Awk "/#/ (print $0 ":\tMay komento sa linyang ito)" /etc/hosts

Ang "//" na elemento sa pattern ay isang paraan upang tukuyin ang isang tugma. Mayroon ding iba pang mga paraan upang matukoy kung ang isang string ay tumutugma. Halimbawa,

Awk "$1 == "#" (i-print ang "linya ay nagsisimula sa hash")" /etc/hosts

ay tutugma sa mga row na ang unang column ay iisang "#". Ang pagkakasunud-sunod ng mga character na "==" ay nangangahulugang isang EXACT MATCH ng BUONG unang column.

Pagbabago para sa kalinawan:

Awk "$1 == "#" (i-print ang $0 "\tline ay nagsisimula sa hash)" /etc/hosts

Sa kabilang banda, kung gusto mo ng bahagyang tugma ng isang partikular na column, gamitin ang operator na "~".

Awk "$1 ~ /#/ (i-print ang "SOMEWHERE there is a hash in column 1")" /etc/hosts

TANDAAN NA ANG UNANG HANAY AY MAARING MATAPOS ANG PUTING ESPACE.

Pagbabago para sa kalinawan:

Awk "$1 ~ /#/ (i-print ang $0 "\tMay hash SOMEWHERE sa column 1)" /etc/hosts

Ang paglalagay ng "#comment" ay tutugma

Ang paglalagay ng "#comment" ay tutugma DIN

Kung gusto mo ng isang partikular na tugma ng "isang string na nagsisimula sa eksaktong # at isang puwang" na gagamitin mo

Awk "/^# / (gumawa ng isang bagay)"

Maramihang tugma

Ipoproseso ng Awk ang LAHAT NG PATTERNS na tumutugma sa kasalukuyang linya. Kaya kung gagamitin natin ang sumusunod na halimbawa,

Awk " /#/ (i-print ang "May komento") $1 == "#" (i-print ang "Komento sa unang column") /^# / (i-print ang "Komento sa pinakasimula") " /etc/hosts

TATLONG mga entry ang ilalabas para sa isang linya tulad ng sumusunod:

# Ito ay isang komento

DALAWANG entry para sa

# Ito ay isang naka-indent na komento

at isa lamang para sa

1.2.3.4 hostname # isang huling komento

Pagsubaybay sa konteksto

Hindi lahat ng mga string ay ginawang pantay, kahit na magkapareho ang hitsura nila. Minsan gusto mong gumawa ng isang bagay sa isang string depende sa mga linya na nauna dito.

Dito mabilis na halimbawa na nagpi-print ng mga linyang "ADDR" kung wala ka sa seksyong "lihim".

Awk " /secretstart/ ( secret=1) /ADDR/ ( if(secret==0) print $0 ) /* $0 is buong linya*/ /secretend/ ( sikreto=0) "

Ang sumusunod ay magpi-print ng mga nilalaman na naglalaman ng "ADDR" sa loob maliban kung ang string na "secretstart" ay nakita. MAHALAGA ANG ORDER. Halimbawa, kung isusulat mo ito tulad nito:

Awk " /ADDR/ ( if(secret==0) print $0 ) /* $0 ang kumpletong linya */ /secretstart/ ( secret=1) /secretend/ ( secret=0) "

at ibigay ang sumusunod na input

ADDR isang normal na addr secretstart ADDR isang secret addr ADDR isa pang secret addr isang third secret ADDR secretend ADDR normal din

pagkatapos ay ipi-print ang unang "lihim" na addr. Given na ang orihinal na halimbawa ay itatago ang parehong mga lihim.

Ikatlong Bahagi: Mga Espesyal na Variable

Napag-usapan na natin ang karaniwang awk syntax. Ngayon simulan natin ang pagtingin sa mga naka-istilong bagay.

Ang awk ay may "espesyal" na tumutugmang mga string: " MAGSIMULA"At" WAKAS"

Direktiba MAGSIMULA tumawag nang isang beses bago basahin ang anumang mga hilera mula sa data, hindi na mauulit.

Direktiba WAKAS tinawag pagkatapos basahin ang lahat ng linya. Kung maraming file ang ibinigay, tatawagin lamang ito pagkatapos makumpleto ang pinakabagong file.

Karaniwang gagamitin mo MAGSIMULA para sa iba't ibang initialization, at WAKAS para sa pagbubuod o paglilinis.

BEGIN ( maxerrors=3 ; logfile=/var/log/something ; tmpfile=/tmp/blah) ... ( blah blah blah ) /^header/ ( headercount += 1 ) END ( printf("kabuuang header counted=% d\n", bilang ng header);

Bibilangin ng halimbawang ito ang dami ng beses na lumabas ang "header" sa input file at i-print ang kabuuan pagkatapos lang maproseso ang buong file.

Ang AWK ay mayroon ding maraming iba pang mga espesyal na halaga na magagamit mo sa seksyong (). Halimbawa,

I-print ang NF

ay magbibigay sa iyo ng kabuuang bilang ng mga column (Number of Fields) sa kasalukuyang row. FILENAME ay ang kasalukuyang filename, na nagpapahiwatig na ang filename ay ipinasa sa awk sa halip na isang pipe na ginagamit.

HINDI KA MAGBABAGO NF sa sarili.

Pareho sa variable NR, na nagsasabi sa iyo kung ilang row ang iyong naproseso. (“Bilang ng mga Tala” - Bilang ng mga tala)

Mayroong iba pang mga espesyal na variable, kahit na maaari mong baguhin sa gitna ng programa.

Ikaapat na Bahagi: Mga Simpleng Halimbawa ng Awk

Upang ilarawan at patibayin ang sinabi, tingnan natin ang ilan tiyak na mga halimbawa. Para sa kanila kakailanganin namin ng tatlong maliliit na text file.

Para sa mga sumusunod na halimbawa, gumawa tayo ng field_data.txt file na may sumusunod na nilalaman:

Ang mga rosas ay pula, Violets ay asul, Asukal ay matamis, At gayon din ikaw.

Echo -e "Ang mga rosas ay pula,\nAng mga violet ay asul,\nAng asukal ay matamis,\nAt ikaw din." >field_data.txt

Gumawa tayo ng file letters.txt na may mga sumusunod na nilalaman

A bb ccc dddd ggg hh i

SA command line ito ay maaaring gawin tulad nito:

Echo -e "a\nbb\nccc\ndddd\nggg\nhh\ni" > letters.txt

Panghuli, gumawa tayo ng mail-data file na may sumusunod na nilalaman:

Amelia 555-5553 [email protected] F Anthony 555-3412 [email protected] Becky 555-7685 [email protected] Isang Bill 555-1675 [email protected] Isang Broderick 555-0542 [email protected] R Camilla 555-2912 [email protected] R Fabius 555-1234 [email protected] F Julie 555-6699 [email protected] F Martin 555-6480 [email protected] Isang Samuel 555-3430 [email protected] Isang Jean-Paul 555-2127 [email protected] R

Magagawa ito sa command line tulad nito:

Wget https://raw.githubusercontent.com/tdhopper/awk-lessons/master/data/mail-data -O mail-data

Simpleng pattern (sample)

Kung kailangan namin ng mga linyang mas mahaba sa dalawang character at gusto naming gamitin ang default na aksyon ( print), pagkatapos ay makukuha natin:

Awk "length $0 > 2" letters.txt bb ccc dddd ggg hh

$0 ay isang built-in na variable na naglalaman ng isang string.

Simpleng function

Kung hindi kami tumukoy ng pattern, magkatugma ang bawat linya. Ang isang maliit na aksyon ay ang pag-print ng bawat linya:

Awk "( print )" letters.txt a bb ccc dddd ggg hh i

Gamit ang function haba bilang ating aksyon, makukuha natin ang haba ng bawat linya:

Awk "( haba ng pag-print )" letters.txt 1 2 3 4 3 2 1

Nalalapat ang pagkilos na ito nang walang kondisyon sa buong row. Maaari rin naming tukuyin ito nang tahasan:

Awk "( haba ng pag-print $0 )" letters.txt 1a 2bb 3ccc 4dddd 3ggg 2hh 1i

Ang Awk ay may mga espesyal na kontrol para sa pagpapatupad ng ilang code bago magsimula ang pag-input ng file at pagkatapos makumpleto ang file.

Awk "BEGIN ( print "HI") ( print $0 ) END ( print "BYE!" )" letters.txt HI a bb ccc dddd ggg hh i BYE!

Maaari tayong magkaroon mas maraming elemento kontrol habang nagpi-print gamit printf.

Awk "BEGIN ( printf "%-10s %s\n", "Pangalan", "Number" \ printf "%-10s %s\n", "----", "------" ) \ ( printf "%-10s %s\n", $1, $2 )" mail-data Name Number ---- ------ Amelia 555-5553 Anthony 555-3412 Becky 555-7685 Bill 555-1675 Broderick 555-0542 Camilla 555-2912 Fabius 555-1234 Julie 555-6699 Martin 555-6480 Samuel 555-3430 Jean-Paul 555-2127

Pinagsasama-sama ang mga sample at function

Siyempre, maaaring pagsamahin ang mga pattern at function para mailapat lang ang function kung tumugma ang string sa pattern.

Maaari naming i-print ang haba ng lahat ng mga linya na mas mahaba sa 2 character.

Awk "haba($0) > 2 ( haba ng pag-print($0) )" letters.txt 3 4 3

Sa katunayan, hindi natin kailangang limitahan ang Awk sa isang pattern lang! Maaari tayong magkaroon ng arbitrary na bilang ng mga pattern, na nililimitahan ng mga semicolon o mga bagong linya:

Awk "length($0) > 2 ( print "Long: " length($0) ); length($0)< 2 { print "Short: " length($0) }" letters.txt Short: 1 Long: 3 Long: 4 Long: 3 Short: 1

Maraming field

Idinisenyo ang Awk para sa simpleng pagpoproseso ng data na may maraming magkakasunod na field. Maaaring tukuyin ng susi ang field separator -F.

Isang halimbawa ng isang file kung saan ang delimiter ay isang puwang:

Awk "( print )" field_data.txt Ang mga rosas ay pula, Ang mga violet ay asul, Ang asukal ay matamis, At ikaw din.

Kung tutukuyin namin ang isang field separator, maaari naming i-print ang pangalawang field ng bawat linya:

Awk -F " " "( print $2 )" field_data.txt are are is so

Hindi kami makakakuha ng error kung ang row ay walang katugmang field; ipapakita lamang sa amin ang isang walang laman na linya:

Awk -F " " "( print $4 )" field_data.txt ka.

Dahil ang default na separator ay isang puwang, ang nakaraang utos ay magbibigay ng eksaktong parehong resulta nang hindi gumagamit ng opsyon -F. Para sa mas makabuluhang halimbawa, gumawa tayo ng isa pang file rates.txt na may sumusunod na nilalaman:

Pilcrow,Humphrey,3 Pilcrow,Zora,1 Plinius,Oldone,4 Razniecki,Anton,7 Russell,Bertrand,0

Ngayon ipinapahiwatig namin bilang isang separator , (kuwit) at ipakita ang mga nilalaman ng pangalawang hanay:

Awk -F "," "( print $2 )" rates.txt Humphrey Zora Oldone Anton Bertrand

Ang delimiter expression ay binibigyang kahulugan bilang isang regular na expression.

Awk -F "((so)?are|is) " "(print "Field 1: " $1 "\nField 2: " $2)" field_data.txt Field 1: Roses Field 2: red, Field 1: Violets Field 2 : asul, Field 1: Sugar Field 2: sweet, Field 1: At Field 2: ikaw.

Mga Regular na Ekspresyon

Ang mga pattern ay maaaring mga regular na expression, hindi lamang mga built-in na function.

Magagamit natin mga regular na expression para mahanap ang lahat ng salita sa Unix world na may 5 vowels sa isang hilera.

Awk "/(5)/" /usr/share/dict/words cadiueio Chaouia euouae Guauaenok

Pagpasa ng mga Variable sa isang Programa

Pagpipilian -v para sa Awk ay nagbibigay-daan sa amin na ipasa ang mga variable sa programa. Halimbawa, magagamit natin ito para sa mga hard code constants.

Awk -v pi=3.1415 "BEGIN ( print pi )" 3.1415

Magagamit din natin -v upang ipasa ang mga variable ng Bash bilang mga variable ng Awk

Awk -v user=$USER "BEGIN ( print user )" mial

Kung-ibang mga expression

Kung-kung hindi ang mga expression sa Awk ay ganito ang hitsura:

Kung (kondisyon) katawan-kung gayon

Halimbawa:

Printf "1\n2\n3\n4" | awk \ "( \ kung ($1 % 2 == 0) i-print ang $1, "ay even"; \ else i-print ang $1, "ay kakaiba" \ )" 1 ay kakaiba 2 ay even 3 ay kakaiba 4 ay even

Mga cycle

Kasama sa Awk ang ilang expression ng loop: habang, gawin habang At para sa.

Mayroon silang inaasahang C syntax.

Awk\"BEGIN(\i=0;\while(i< 5) { print i; i+=1; } \ }" 0 1 2 3 4 awk \ "BEGIN { \ i = 0; \ do { print i; i+=1; } while(i < 0) \ }" 0 awk \ "BEGIN { \ i = 0; \ for(i = 0; i<5; i++) print i \ }" 0 1 2 3 4

para sa maaari ring tukuyin ang isang loop sa pamamagitan ng array key, alin tatalakayin mamaya.

Ikalimang Bahagi: Mga Function ng Pagtawag

Ang susunod na bahagi ng AWK ay ang lahat ng mga espesyal na built-in na function nito.

Ang AWK ay may mga tampok na magpapasaya sa karaniwang C programmer. Narito ang mga bagay tulad ng sin()/cos()/tan(), rand(),index(), sprintf(), tolower(), system()

Ang mga function ay nakagrupo at maaaring matingnan bilang mga sumusunod:

Matematika

+, -, /, *, sin(), cos(), tan(), atan(), sqrt(), rand(), srand()

Nagsasalita sila para sa kanilang sarili, at least gusto kong isipin.

Awk -v pi=3.1415 "BEGIN ( print exp(1), log(exp(1)), sqrt(2), sin(pi), cos(pi), atan2(pi, 2) )" 2.71828 1 1.41421 9.26536 e-05 -1 1.00387

Ang programa ay maaaring bumuo random na numero sa hanay (0, 1).

Bilang default, nagsisimula ang Awk sa parehong simula (binhi) para sa Awk. Ang pagpapatakbo ng command na ito nang dalawang beses sa isang hilera ay magbabalik ng parehong resulta:

Awk "BEGIN ( print rand(); print rand() )" 0.237788 0.291066

Upang itakda ang simula (binhi) maaari mong gamitin ang srand function:

Awk "BEGIN ( srand(10); print rand(); print rand() )" 0.255219 0.898883 awk "BEGIN ( srand(10); print rand(); print rand() )" 0.255219 0.898883

Function int ibinabalik ang "pinakamalapit na integer sa x sa pagitan ng x at zero, na ang nangungunang zero ay itinapon."

Awk "BEGIN ( print "int(0.9) = " int(0.9); print "int(-0.9) = " int(-0.9) )" int(0.9) = 0 int(-0.9) = 0

Pagmamanipula ng string

  • index() ay magsasabi sa iyo kung, at kung gayon kung saan, ang isang string ay nangyayari sa loob ng isang substring.
  • tugma() katulad, ngunit gumagana para sa mga regular na expression.
  • sprintf() ay nagbibigay sa iyo ng mga paraan upang i-format ang output at gawin ang mga conversion sa daan. Dapat itong pamilyar sa sinumang gumamit ng printf() sa C. Halimbawa,
newstring=sprintf("isa ay isang numero %d, dalawa ay isang string %s\n", isa, dalawa);

"i-print ang bagong string%d
"" sabi ni "i-print ang halaga na naaayon sa akin bilang isang decimal na numero"%s

" sabi ni "i-print ang halaga na naaayon sa akin bilang isang string"

Yung. kung gusto mong pagsamahin ang dalawang linya nang walang mga pahinga, ISANG paraan ang gagamitin

  • Newstring=sprintf("%s%s", isa, dalawa) haba()

Function nagbibigay lang sa iyo ng madaling paraan upang mabilang ang bilang ng mga character sa isang linya kung kailangan mo ito. substr(s, m, n) ibabalik ang substring in n -mga character na nagsisimula sa posisyon m

, binibilang mula 1.

Awk "( print $1, substr($1, 2, 3) )" field_data.txt Roses ose Violets iol Sugar uga And nd index(s,t) nagbabalik ng `posisyon sa s kung saan nangyayari ang linya t

Ang pattern para sa index ay hindi isang regular na expression.

Awk "( print $1, index($1, "s") )" field_data.txt Roses 3 Violets 7 Sugar 0 And 0

tugma (mga, r) ibinabalik ang posisyon sa nagbabalik ng `posisyon sa kung saan nangyayari ang regular na expression r, o 0 kung hindi ito nangyari. Mga variable Magsimula At RLENGTH ay nakatakda sa posisyon at haba ng katugmang string.

tugma- Paano yan index maliban na ang pattern ay isang regular na expression.

Awk "( print $1, match($1, "") )" field_data.txt Roses 3 Violets 7 Sugar 1 And 0 # "Maghanap ng tatlo o higit pang mga paulit-ulit na letra" awk "( match($1, "(3)"); print $1, "\tpattern start:", RSTART, "\tpattern end:", RLENGTH )" letters.txt isang pattern start: 0 pattern end: -1 bb pattern start: 0 pattern end: -1 ccc pattern start: 1 pattern pagtatapos: 3 dddd pattern start: 1 pattern end: 3 ggg pattern start: 1 pattern end: 3 hh pattern start: 0 pattern end: -1 i pattern start: 0 pattern end: -1

split(s, a, fs) hinahati ang isang string sa isang hanay ng mga elemento a, a, …, a, at bumabalik ibabalik ang substring in.

Ang paghahati ay ginagawa sa pamamagitan ng regular na pagpapahayag fs o may field separator FS, Kung fs hindi binigay. Hinahati ng walang laman na string bilang field separator ang string sa isang hanay ng mga elemento na character ayon sa karakter.

Awk "BEGIN ( print split("It-was_the-best_of-times", output_array, "[-_]"), output_array, output_array )" 6 ang pinakamaganda

sub(r, t, s) pinapalitan ng kung saan nangyayari ang linya unang paglitaw ng regular na pagpapahayag r nasa linya nagbabalik ng `posisyon sa. Kung hindi ibinigay ang s, pagkatapos ay gamitin $0

nagbabalik ng `posisyon sa ay ang string kung saan nangyayari ang pagpapalit. Sa halip na magbalik ng bagong string na may ginawang kapalit, ibabalik ang bilang ng mga ginawang pagpapalit (0 o 1).

Awk "BEGIN ( s = "It was the best of times, it was the worst of times"; \ print "Num. matches replaced:", sub("times", "gifs", s); \ print s )" Blg. pinalitan ang mga tugma: 1 Ito ang pinakamahusay sa mga gif, ito ang pinakamasama sa mga panahon

gsub ginagawa ang parehong bagay bilang sub maliban na ang lahat ng paglitaw ng regular na expression ay pinalitan; sub At gsub ibalik ang bilang ng mga kapalit.

Awk "BEGIN ( s = "It was the best of times, it was the worst of times"; \ print "Num. matches replaced:", gsub("times", "cats", s); \ print s )" Blg. pinalitan ang mga tugma: 2 Ito ang pinakamahusay sa mga pusa, ito ang pinakamasama sa mga pusa sprintf sprintf(fmt, expr, ...) ay nagbabalik ng string na nagreresulta mula sa pag-format ng expr ... ayon sa printf(3) na format fmt awk "BEGIN ( x = sprintf("[%8.3f]", 3.141592654); print x )" [ 3.142]

Mga function sa antas ng system

sistema() nagbibigay-daan sa iyo na tumawag sa potensyal na ANUMANG maipapatupad na file sa system. Ang target na programa ay maaaring nasa iyong $PATH, o maaari mong tukuyin ito gamit ang isang ganap na landas.

Halimbawa, nakakatakot

System("rm -rf $HOME");

System("/bin/kill 1")

Kung gusto mong gumawa ng mas kumplikadong mga bagay, malamang na magtatapos ka sa paggawa ng isang bagay na tulad nito

Sysstring=sprintf("somecommand %s %s", arg1, arg2);

system(sysstring) malapit () ay isang mahalagang tampok na madalas na napapansin. Ito ay marahil dahil walang halatang tawag bukas() system(sysstring), kaya hindi iniisip ng mga tao ang hamon

. At para sa karamihan ng mga layunin na ito ay hindi kinakailangan. Ngunit DAPAT mong GAWIN ITO kung ikaw ay nakikitungo sa higit sa isang output file.

Binibigyan ka ng Awk ng kakayahang magbukas ng arbitrary na file sa mabilisang paraan. Halimbawa

/^file/ ( print $3 >> $2 )

dapat kunin ang linyang "file output here-is-a-word", buksan ang file na "output" at i-print ang "here-is-a-word" dito.

Ang AWK ay "matalino" dahil sinusubaybayan nito kung anong mga file ang bubuksan mo at PINAnanatili itong bukas. Ipinapalagay na kung binuksan mo ang file nang isang beses, malamang na gagawin mo itong muli. Sa kasamaang palad, nangangahulugan ito na kung magbubukas ka ng MARAMING file, maaari kang maubusan ng mga descriptor ng file. Kaya kapag alam mong tapos ka na sa isang file, isara ito. Kaya upang mapabuti ang halimbawa sa itaas, dapat kang gumamit ng isang bagay tulad ng mga sumusunod na linya:

/^file/ (kung ($2 != oldfile) (close(oldfile) ); print $3 >> $2 ; oldfile = $2; )

Ika-anim na Bahagi: Arrays

Konsepto ng array

Tinitingnan na namin ang mga variable bilang mga pangalan na naglalaman ng isang halaga. Ang mga array ay isang extension ng mga variable. Ang mga array ay mga variable na naglalaman ng higit sa isang halaga. Maaari silang maglaman ng higit sa isang halaga dahil ang bawat halaga ay may sariling numero.

Kung kailangan mong magkaroon ng tatlong halaga, maaari mong sabihin:

Value1="one"; value2="dalawa"; value3="tatlo";

O, maaari mong gamitin

Values="one"; values="two"; values="three";

Ang unang halimbawa ay tatlong magkakaibang variable na may sariling mga pangalan (na naiiba sa isang character). Ang pangalawang halimbawa ay isang array na binubuo ng isang variable, ngunit naglalaman ng maraming value, bawat isa ay may sariling numero.

Kapag gumagamit ng variable bilang array, dapat mong palaging ilakip ang value sa mga square bracket. Maaari kang pumili ng anumang pangalan para sa isang array variable, ngunit mula ngayon ang pangalan na iyon ay maaari LAMANG gamitin para sa isang array. HINDI ka makakagawa ng makabuluhang bagay

Values="one"; values="newvalue";

Gayunpaman, MAAARI mong muling italaga ang mga halaga tulad ng gagawin mo para sa mga normal na variable. Yung. tama ang sumusunod:

Ang kawili-wiling bagay ay, hindi katulad ng ibang mga wika, hindi ka pinipilit na gumamit lamang ng mga numero. Sa mga halimbawa sa itaas, ang ,, ay talagang binibigyang kahulugan bilang [“1”], [“2”], [“3”]. Na nangangahulugan na maaari mo ring gamitin ang iba pang mga string bilang mga identifier, at ituring ang array na halos tulad ng isang database ng solong column. Ang opisyal na pangalan para dito ay "kaugnay na hanay".

Mga Numero["one"]=1; mga numero ["dalawa"]=2; i-print ang mga numero ["isa"]; value="two"; print numbers; value=$1; if(numbers = ""){ print "no such number"; } !}

Kailan at paano gamitin ang mga array

Maaaring may iba't ibang mga kaso kung saan maaari mong piliing gumamit ng mga array. Ang ilang mga tao, kapag nagtatrabaho sa awk, ginagawa nang walang array. Ngunit hindi ito isang ganap na tamang posisyon: para sa mga array mayroong mga espesyal na variable na, halimbawa, ay nagpapakita ng laki nito (ang bilang ng mga halaga sa array), may mga construct na maginhawa para sa pag-enumerate ng mga miyembro ng array, at ang ilang mga function ay nagbabalik ng isang halaga sa anyo ng isang array. Anyway, tingnan natin ang ilang halimbawa na maaaring maging kapaki-pakinabang.

Nagse-save ng impormasyon para magamit sa ibang pagkakataon

Kapag gumagamit ng awk sa isang malaking shell script, maaari mong i-save ang impormasyon sa isang pansamantalang file. Ngunit maaari mong i-save ang mga salitang kailangan mo sa memorya at pagkatapos ay i-print ang lahat ng ito sa dulo, na magiging mas mabilis kaysa sa paggamit ng isang pansamantalang file.

/especial/( savedwords=$2; lnum+=1; ) END ( count=0; while(na-save na salita != "") ( print count, savewords; count+=1; ) )

Sa halip na magpakita lamang ng mga salita, maaari mong gamitin ang seksyong END para gawin ang anumang karagdagang pagproseso na maaaring kailanganin mo bago ipakita ang mga ito.

Kung nais mong magtalaga ng isang natatanging index sa mga halaga (upang maiwasan ang mga duplicate), maaari mong karaniwang sumangguni sa kanilang mga halaga sa pamamagitan ng kanilang sariling mga hilera. O, halimbawa, mag-save ng array na may column 3, na na-index ng katumbas na value sa column 2.

( threecol[$2]=$3 ) END ( para sa (v sa threecol) ( print v, threecol[v] ) )

Mga array at split()

Ang iba pang pangunahing dahilan para gumamit ng mga array ay kung gusto mong gumawa ng mga subfield. Sabihin nating mayroon kang isang row na may ilang malalaking dibisyon at ilang maliliit na dibisyon. Sa madaling salita, ang mga top level na field ay pinaghihiwalay ng mga puwang, ngunit pagkatapos ay makakakuha ka ng mas maliliit na salita na pinaghihiwalay ng mga colon.

Ito ay isang variable:field:type line Maaaring mayroong maramihang:type:values ​​​​dito

Sa halimbawa sa itaas, ang ikaapat na field, na pinaghihiwalay ng isang espasyo, ay may mga subfield na pinaghihiwalay ng mga tutuldok. Ngayon, sabihin nating gusto mong malaman ang halaga ng pangalawang subfield sa ikaapat na malaking field. Ang isang paraan upang gawin ito ay ang tumawag sa dalawang awks na konektado ng pipe:

Awk "(print $4)" | awk -F: "(print $2)"

Ang isa pang paraan ay ang pagbabago ng halaga ng "FS" sa mabilisang, na naglalaman ng field separator (tila hindi ito gumagana sa lahat ng pagpapatupad ng awk):

Awk "( newline=$4; fs=FS; FS=":"; $0=newline; print $2 ; FS=fs; )"

Ngunit maaari mo ring gawin ito sa mga array gamit ang split() function na tulad nito:

Awk "( newline=$4; split(newline,subfields,":"); print subfields) "

Sa kasong ito, ang paggamit ng array ay ang pinakakaraniwan at marahil pinaka-eleganteng paraan para gawin ito.

Kaya, ang Awk ay nagbibigay ng limitadong bilang ng mga istruktura ng data. Bilang karagdagan sa mga variable ng scalar at string, ang wika ay may built-in na napakalaking istraktura ng data. Bagama't opisyal na tinatawag na "arrays", ang istrukturang ito ay talagang isang nauugnay na array, katulad ng dict data structure sa Python.

Hindi kailangang masimulan ang mga array. Maaari ka lamang magsimulang magtalaga ng mga halaga. Tandaan na ang mga susi ay maaaring mga numero o mga string.

Awk "BEGIN ( \ a = 1.1; \ a = 0; \ a["DOG"] = "CAT"; \ print a, a, a["DOG"] \ )" 1.1 0 CAT

Hindi magpi-print ng variable ang Awk nang walang index:

Awk "BEGIN ( \a["DOG"] = "CAT"; \print a\ )" awk: cmd. line:3: fatal: subukang gumamit ng array `a" sa kontekstong scalar

Bagama't maaari tayong mag-loop sa pamamagitan ng key gamit para sa:

Awk "BEGIN ( \ a = 1.1; \ a = 0; \ a["DOG"] = "CAT"; \ for(k in a) print(a[k]) \ )" CAT 0 1.1

Ikapitong Bahagi: AWK at Shells (sh/ksh/bash/csh)

Minsan maaaring hindi sapat ang functionality ng AWK. Sa kasong ito, maaari mong isama ang awk sa iyong shell script. Nasa ibaba ang ilang halimbawa kung paano ito magagawa.

Simpleng konklusyon

Minsan gusto mong gamitin ang awk bilang isang formatter, at i-dump ang output nang direkta sa user Ang sumusunod na script ay kumukuha ng username bilang argumento at gumagamit ng awk upang i-dump ang impormasyon ng user mula sa /etc/passwd.

Tandaan: Tandaan na sa script ang mga solong quote ay pinalawak (hindi nested) at sa pagitan ng dalawang pinalawak na pares ng mga solong quote ay may variable na $1 (ang pangalawa), na sa kasong ito ay ang script argument, habang ang $1 ay bahagi ng syntax $1 (ibig sabihin ang unang field sa linya).

#!/bin/sh habang [ "$1" !="" ] ; gawin awk -F: "$1 == ""$1"" ( print $1,$3) " /etc/passwd shift tapos na

Pagtatalaga ng mga variable ng awk output shell

Minsan gusto naming gumamit ng awk para lamang sa isang mabilis na paraan upang itakda ang halaga ng isang variable. Gamit ang passwd na tema, mayroon kaming paraan upang malaman ang shell para sa user at tingnan kung kasama ito sa listahan ng mga opisyal na shell.

Muli, pansinin kung paano isinara ang mga solong quote sa awk expression Pagkatapos ng closed (second) quote, ang $1 ay isang variable na ipinapasa ang halaga ng unang argumento sa script, hindi bahagi ng awk syntax.

#!/bin/sh user="$1" kung [ "$user" == "" ] ; pagkatapos ay echo ERROR: kailangan ng username ; labasan ; fi usershell=`awk -F: "$1 == ""$1"" ( print $7) " /etc/passwd` grep -l $usershell /etc/shells kung [ $? -ne 0 ] ; pagkatapos ay echo ERROR: shell $usershell para sa user $user wala sa /etc/shells fi

Iba pang mga alternatibo:

# Tingnan ang "man regex" usershell=`awk -F: "/^"$1":/ ( print $7) " /etc/passwd` echo $usershell; # Tanging modernong awk lang ang tumatanggap ng -v. Maaaring kailanganin mong gumamit ng "nawk" o "gawk" usershell2=`awk -F: -v user=$1 "$1 == user ( print $7) " /etc/passwd` echo $usershell2;

Ang pagpapaliwanag ng mga karagdagang pamamaraan sa itaas ay iniiwan bilang takdang-aralin para sa mambabasa :)

Paglilipat ng data sa awk sa pamamagitan ng pipe

Minsan gusto mong ilagay ang awk bilang filter ng data, sa isang malaking program, o bilang isang linyang command na ipinasok sa isang shell prompt. Isang halimbawa ng tulad ng isang command sa isang script (isang listahan ng mga web server log file ay ipinapasa bilang mga argumento sa script, dahil ang pag-log ay nako-customize at ang mga log ay maaaring magkaroon ng ibang istraktura; upang gumana sa mga partikular na kaso, ang mga command ay maaaring kailanganin dapat ayusin):

#!/bin/sh grep -h " /index.html" $* | awk -F\" "(print $4)" | sort -u

  1. Kawili-wiling artikulo, nais kong pasalamatan ka para sa iyong mga pagsisikap.

    Natagpuan ko na ito ay hindi tumpak. Kung ipapatupad mo ang linya mula sa halimbawa

    Awk -F " " "( print $2 )" field_data.txt

    ito ay maglalabas ng parehong bagay bilang

    Awk "( print $2 )" field_data.txt

    Ang resulta ay isang halimbawa na may -F hindi maayos na inilarawan.

Isang panimula sa isang kahanga-hangang wika na may kakaibang pangalan

Serye ng Nilalaman:

Sa pagtatanggol sa awk

Sa seryeng ito ng mga artikulo, gagawin kong isang bihasang programmer ng awk ang mambabasa. Sumasang-ayon ako na ang awk ay walang pinakamaganda o pinakauso na pangalan, at ang GNU na bersyon ng awk, na tinatawag na gawk, ay mukhang kakaiba. Ang mga programmer na hindi pamilyar sa wika ay maaaring marinig ang pangalan nito at isipin ang isang paghalu-halo ng sinaunang at lumang code na maaaring magdulot ng kahit na ang pinaka-kaalaman na espesyalista sa UNIX na mabaliw (na nagiging dahilan upang siya ay sumigaw ng "kill -9!" at patuloy na tumakbo para sa kape).

Oo, walang magandang pangalan si awk. Ngunit ito ay isang kahanga-hangang wika. Ang Awk ay idinisenyo para sa pagpoproseso at pag-uulat ng teksto, ngunit mayroon itong maraming mahusay na binuo na mga tampok na nagbibigay-daan sa seryosong programming. Gayunpaman, hindi tulad ng ilang iba pang mga wika, pamilyar ang syntax ng awk at hinihiram ang pinakamahusay mula sa mga wika tulad ng C, python at bash (bagama't pormal na ginawa ang awk bago ang python at bash). Ang Awk ay isa sa mga wikang iyon na, kapag natutunan, ay nagiging mahalagang bahagi ng strategic arsenal ng isang programmer.

Unang hakbang sa awk

Magsimula tayo at subukang mag-eksperimento sa awk upang makita kung paano ito gumagana. Sa command line, ipasok ang sumusunod na command:

$awk "( print )" /etc/passwd

Dapat ipakita ng resulta ang mga nilalaman ng /etc/passwd file. Ngayon - isang paliwanag sa ginawa ni awk. Kapag tumatawag sa awk, tinukoy namin ang /etc/passwd bilang input file. Nang tumakbo kami ng awk, pinoproseso nito ang print command para sa bawat linya sa /etc/passwd sa pagkakasunud-sunod. Ang lahat ng output ay ipinadala sa stdout at nakuha namin ang parehong resulta tulad ng cat /etc/passwd. Ngayon ipaliwanag natin ang (print) block. sa awk braces ay ginagamit sa pagpapangkat ng mga bloke ng teksto, tulad ng sa C. Ang aming bloke ng teksto ay mayroon lamang isang print command. Sa awk, ang print command na walang karagdagang mga parameter ay nagpi-print ng buong nilalaman kasalukuyang linya.

Narito ang isa pang halimbawa ng isang awk program na gumagawa ng parehong bagay:

$awk "( print $0 )" /etc/passwd

Sa awk, ang variable na $0 ay kumakatawan sa buong kasalukuyang linya, kaya ang pag-print at pag-print ng $0 ay eksaktong parehong bagay. Kung gusto mo, maaari kang lumikha ng isang programa sa awk na maglalabas ng data na ganap na hindi nauugnay sa input data. Narito ang isang halimbawa:

$awk "( print "")" /etc/passwd

Kapag ipinasa mo ang string "" sa print command, palagi itong nagpi-print ng walang laman na string. Kung susubukan mo ang script na ito, makikita mo na ang awk ay naglalabas ng isang blangkong linya bawat linya sa /etc/passwd. Nangyayari ito muli dahil nagpapatupad ang awk ng script para sa bawat linya sa input file. Narito ang isa pang halimbawa:

$awk "( print "hiya")" /etc/passwd

Kung patakbuhin mo ang script na ito, pupunuin nito ang screen ng mga salitang "yay". :)

Maramihang mga patlang

Ang Awk ay angkop para sa pagproseso ng text na hinati sa maraming lohikal na field, at ginagawang madali ang pag-access sa bawat indibidwal na field mula sa loob ng isang awk script. Ang sumusunod na script ay magpi-print ng listahan ng lahat ng mga account sa system:

$ awk -F":" "( print $1 )" /etc/passwd

Sa awk call sa halimbawa sa itaas, ang –F na opsyon ay tumutukoy sa ":" bilang field separator. Kapag pinoproseso ang print $1 command, ini-print ng awk ang unang field na makikita sa bawat linya ng input file. Narito ang isa pang halimbawa:

$ awk -F":" "( print $1 $3 )" /etc/passwd

Narito ang isang snippet mula sa screen output ng script na ito:

halt7 operator11 root0 shutdown6 sync5 bin1 ....atbp.

Gaya ng nakikita mo, inilalabas ng awk ang una at pangatlong field ng /etc/passwd file, na kung saan ay ang username at uid field, ayon sa pagkakabanggit. Gayunpaman, kahit na gumagana ang script, hindi ito perpekto - walang mga puwang sa pagitan ng dalawang field ng output! Maaaring inaasahan ng mga nakasanayan sa programming sa bash o python ang pag-print ng $1 $3 na utos na magpasok ng puwang sa pagitan ng dalawang field na ito. Gayunpaman, kapag lumitaw ang dalawang linya sa tabi ng isa't isa sa isang awk program, pinagsasama-sama ng awk ang mga ito nang hindi nagdaragdag ng puwang sa pagitan nila. Ang sumusunod na utos ay maglalagay ng puwang sa pagitan ng mga patlang:

$ awk -F":" "( print $1 " " $3 )" /etc/passwd

Kapag tinawag ang print sa ganitong paraan, pinagsasama nito ang $1 , " " at $3 sa serye, na gumagawa ng output na nababasa ng tao sa screen. Siyempre, maaari rin kaming magpasok ng mga field label kung kinakailangan:

$ awk -F":" "( print "username: " $1 "\t\tuid: " $3")" /etc/passwd

Bilang resulta, nakukuha namin ang sumusunod na konklusyon:

username: stop uid:7 username: operator uid:11 username: root uid:0 username: shutdown uid:6 username: sync uid:5 username: bin uid:1 ....etc.

Mga panlabas na script

Ang pagpasa ng mga script sa awk bilang mga argumento ng command line ay maaaring maging maginhawa para sa maliliit na one-liner, ngunit pagdating sa mga kumplikadong multi-line na programa, tiyak na mas mahusay na buuin ang script bilang isang panlabas na file. Maaari mong ituro ang awk sa script file na ito gamit ang -f na opsyon:

$ awk -f myscript.awk myfile.in

Ang paglalagay ng mga script sa hiwalay na mga text file ay nagbibigay-daan din sa iyong samantalahin ang mga karagdagang benepisyo ng awk. Halimbawa, ang sumusunod na multi-line na script ay gumagawa ng parehong bagay tulad ng isa sa aming mga nakaraang one-liner - nagpi-print ng unang field ng bawat linya mula sa /etc/passwd:

MAGSIMULA ( FS=":") ( print $1 )

Ang pagkakaiba sa pagitan ng dalawang pamamaraang ito ay kung paano namin tinukoy ang field separator. Sa script na ito, ang field separator ay panloob na tinukoy ng program mismo (sa pamamagitan ng pagtatakda ng FS variable), samantalang sa aming nakaraang halimbawa, ang FS ay na-configure sa pamamagitan ng pagpasa sa awk ng -F":" na opsyon sa command line. Karaniwang pinakamainam na tukuyin ang field separator sa loob mismo ng script, dahil lang hindi nito kakailanganing tandaan mo ang isa pang argumento ng command line. Titingnan natin ang variable ng FS nang mas detalyado mamaya sa artikulong ito.

BEGIN at END block

Karaniwang pinapagana ng awk ang bawat bloke sa teksto ng script nang isang beses para sa bawat linya ng pag-input. Gayunpaman, madalas na may mga sitwasyon sa programming kung saan kailangan mong magsagawa ng initialization code bago simulan ng awk ang pagproseso ng text mula sa isang input file. Para sa mga ganitong kaso, ang awk ay nagbibigay ng kakayahang tumukoy ng isang BEGIN block. Ginamit namin ang BEGIN block sa nakaraang halimbawa. Dahil ang BEGIN block ay pinoproseso bago simulan ng awk ang pagpoproseso ng input file, ito ay isang magandang lugar upang simulan ang isang FS (field separator) na variable, mag-output ng isang header, o mag-initialize ng iba pang mga global variable na gagamitin mamaya sa programa.

Nagbibigay din ang Awk ng isa pang espesyal na bloke na tinatawag na END block. Isinasagawa ng Awk ang block na ito pagkatapos maproseso ang lahat ng linya sa input file. Karaniwan, ang isang END block ay ginagamit upang magsagawa ng mga panghuling kalkulasyon o mga resulta ng output na dapat lumabas sa dulo ng stream ng output.

Mga regular na expression at block

Binibigyang-daan ka ng Awk na gumamit ng mga regular na expression upang piliing magsagawa ng mga partikular na bloke ng isang programa depende sa kung ang regular na expression ay tumutugma sa kasalukuyang linya. Narito ang isang halimbawang script na nagpi-print lamang ng mga linyang iyon na naglalaman ng sequence ng character na foo:

/foo/ (print)

Siyempre, maaari kang gumamit ng mas kumplikadong mga regular na expression. Narito ang isang script na maglalabas lamang ng mga string na naglalaman ng float:

/+\.*/ ( print )

Mga Expression at Block

Mayroong maraming iba pang mga paraan upang piliing isagawa ang isang bloke ng isang programa. Maaari naming ilagay ang anumang Boolean expression bago ang isang bloke ng programa upang makontrol ang pagpapatupad ng bloke na iyon. Magpapatupad lang ng program block ang Awk kung ang dating Boolean na expression ay magiging true. Ang sumusunod na halimbawang script ay maglalabas ng ikatlong field ng lahat ng linya kung saan ang unang field ay fred . Kung ang unang field ng kasalukuyang linya ay hindi fred , ipagpapatuloy ng awk ang pagproseso ng file at hindi maglalabas ng print statement para sa kasalukuyang linya: :

$1 == "fred" ( print $3 )

Nag-aalok ang Awk ng buong hanay ng mga operator ng paghahambing, kabilang ang karaniwang "==", "<", ">", "<=", ">=" at "!=". Bilang karagdagan, ang awk ay nagbibigay ng "~" at "!~" na mga operator, na nangangahulugang "mga tugma" at "hindi tumutugma." Inilalagay nila ang variable sa kaliwa ng operator at ang regular na expression sa kanan nito Narito ang isang halimbawa kung saan ang pangatlong field lang ng isang linya ang output kung ang ikalimang field ng parehong linya ay naglalaman ng root sequence ng character:

$5 ~ /root/ ( print $3 )

Mga pahayag na may kondisyon

Nagbibigay din ang Awk ng napakagandang C-like if na mga pahayag. Kung nais mo, maaari mong muling isulat ang nakaraang script gamit ang kung:

( kung ($5 ~ /root/) ( print $3 ) )

Parehong gumagana ang mga script. Sa unang halimbawa, ang boolean na expression ay nasa labas ng block, habang sa pangalawang halimbawa, ang block ay isinasagawa para sa bawat input line, at pinili namin ang print command gamit ang isang if statement, at maaari mong piliin ang isa na pinakamahusay na pinagsama sa iba pang mga bahagi ng script.

Narito ang isang mas kumplikadong halimbawa ng isang if statement sa awk. Tulad ng nakikita mo, kahit na may mga kumplikadong nested na kondisyon, kung ang mga pahayag ay mukhang magkapareho sa kanilang mga katapat na C:

( kung ($1 == "foo") ( kung ($2 == "foo") ( print "uno") iba pa (print "isa") ) iba kung ($1 == "bar") (print "dalawa") iba pa (i-print ang "tatlo"))

Gamit ang mga pahayag na if, maaari nating baguhin ang code na ito:

! /matchme/ ( print $1 $3 $4 )( kung ($0 !~ /matchme/) ( print $1 $3 $4 ) )

Ang parehong mga script ay magpi-print lamang ng mga linyang iyon Hindi naglalaman ng pagkakasunod-sunod ng character matchme . At sa kasong ito, masyadong, maaari kang pumili ng isang paraan na mas mahusay na gumagana sa isang partikular na programa. Pareho silang gumagawa ng parehong bagay.

Binibigyan ka rin ng Awk ng kakayahang gamitin ang mga Boolean operator na "||" (“lohikal O”) at “&&” (“lohikal na AT”), na nagbibigay-daan sa iyong lumikha ng mas kumplikadong mga Boolean na expression:

($1 == "foo") && ($2 == "bar") ( print )

Ang halimbawang ito ay maglalabas lamang ng mga linya kung saan ang unang field ay foo At ang pangalawang field ay bar.

Mga variable na numero!

Sa ngayon ay naka-print na kami ng alinman sa mga variable ng string, buong mga string, o mga partikular na field. Gayunpaman, binibigyan din kami ng awk ng kakayahang magsagawa ng mga paghahambing sa parehong mga integer at mga numero ng floating point. Gamit ang mathematical expression, napakadaling magsulat ng script na binibilang ang bilang ng mga walang laman na linya sa isang file. Narito ang isang script:

MAGSIMULA ( x=0 ) /^$/ ( x=x+1 ) END ( i-print ang "Nakahanap " x " mga walang laman na linya. :)") )

Sa BEGIN block, sinisimulan namin ang aming integer variable x sa zero. Pagkatapos, sa tuwing makakatagpo ang awk ng walang laman na linya, isasagawa nito ang statement x=x+1 , dagdagan ang x ng 1. Kapag naproseso na ang lahat ng linya, isasagawa ang END block, at ipi-print ng awk ang panghuling kabuuan, na nagpapahiwatig ang bilang ng mga walang laman na linya na natagpuan.

Mga variable ng string

Ang isa sa mga magagandang bagay tungkol sa mga variable ng awk ay ang mga ito ay "plain at lowercase." Tinatawag ko ang mga variable ng awk na "string" dahil ang lahat ng mga variable ng awk ay panloob na naka-imbak bilang mga string. Kasabay nito, ang mga variable ng awk ay "simple" dahil maaari kang gumawa ng matematika sa isang variable, at kung naglalaman ito ng isang wastong string ng numero, awtomatikong aayusin ng awk ang pag-convert ng string sa isang numero. Upang makita kung ano ang ibig kong sabihin, tingnan ang halimbawang ito:

x="1.01" # Ginawa namin ang x na naglalaman ng *string* "1.01" x=x+1 # Nagdagdag lang kami ng 1 sa *string* print x # Comment pala ito :)

Awk ay maglalabas ng:

2.01

Nakaka-curious! Bagama't itinalaga namin ang string value na 1.01 hanggang x, nakapagdagdag pa rin kami ng isa dito. Hindi namin magawa ito sa bash o python. Una sa lahat, hindi sinusuportahan ng bash ang floating point arithmetic. At habang ang bash ay may mga variable na "string", hindi sila "simple"; Upang makagawa ng anumang matematika, hinihiling sa amin ng bash na ibalot ang aming mga kalkulasyon sa mga pangit na $() construct. Kung gumagamit kami ng python, kakailanganin naming tahasang i-convert ang aming string 1.01 sa isang floating point value bago gumawa ng anumang mga kalkulasyon dito. Bagama't hindi ito mahirap, dagdag na hakbang pa rin ito. Sa kaso ng awk, lahat ng ito ay awtomatikong ginagawa, at ginagawa nitong maganda at malinis ang aming code. Kung kailangan naming i-square ang unang field ng bawat input string at magdagdag ng isa dito, gagamit kami ng script na tulad nito:

( print ($1^2)+1 )

Kung mag-eksperimento ka nang kaunti, makikita mo na kung ang isang variable ay walang wastong numero, ituturing ng awk ang variable na iyon bilang isang numeric zero kapag sinusuri ang isang mathematical expression.

Maraming operator

Ang isa pang magandang tampok ng awk ay ang kumpletong hanay ng mga mathematical operator. Bilang karagdagan sa karaniwang pagdaragdag, pagbabawas, pagpaparami, at paghahati, ang awk ay nagbibigay sa amin ng kakayahang gamitin ang dating ipinakitang exponent operator na "^", ang integer division remainder operator "%" at marami pang ibang maginhawang assignment operator na hiniram mula sa C.

Kabilang dito ang mga operator bago at pagkatapos ng incremental/decremental na pagtatalaga (i++, --foo), mga operator ng pagtatalaga na may karagdagan/pagbabawas/pagpaparami/dibisyon (a+=3, b*=2, c/=2.2, d-=6.2) . Ngunit hindi lang iyon - mayroon din kaming maginhawang mga operator ng pagtatalaga na may pagkalkula ng natitirang bahagi ng integer division at exponentiation (a^=2, b%=4).

Mga separator ng field

Ang awk ay may sariling hanay ng mga espesyal na variable. Binibigyang-daan ka ng ilan sa mga ito na i-fine-tune kung paano gumagana ang awk, habang ang iba ay naglalaman ng mahalagang impormasyon sa pag-input. Natalakay na namin ang isa sa mga espesyal na variable na ito, ang FS. Gaya ng nabanggit kanina, binibigyang-daan ka ng variable na ito na tukuyin ang pagkakasunud-sunod ng mga character na ituturing ng awk bilang field separator. Kapag ginamit namin ang /etc/passwd bilang input, ang FS ay nakatakda sa ":". Ito ay naging sapat na, ngunit ang FS ay nagbibigay sa amin ng higit na kakayahang umangkop.

Ang halaga ng FS variable ay hindi kailangang maging isang character; maaari itong italaga ng isang regular na expression na tumutukoy sa pattern ng character ng anumang haba. Kung pinoproseso mo ang mga field na pinaghihiwalay ng isa o higit pang mga character ng tab, dapat na i-configure ang FS bilang mga sumusunod:

FS="\t+"

Sa itaas ginamit namin espesyal na karakter regular na expression na "+" na nangangahulugang "isa o higit pang mga paglitaw ng nakaraang character".

Kung ang mga field ay pinaghihiwalay ng puting espasyo (isa o higit pang mga puwang o tab), maaari mong itakda ang FS sa sumusunod na regular na expression:

FS="[[:space:]+]"

Habang gagana ang setup na ito, hindi ito kinakailangan. Bakit? Dahil ang default na value ng FS ay isang space character, na binibigyang-kahulugan ng awk bilang "isa o higit pang mga puwang o tab." Sa aming partikular na halimbawa, ang default na halaga ng FS ay eksakto kung ano ang kailangan namin!

Wala ring problema sa mga kumplikadong regular na expression. Kahit na ang mga tala ay pinaghihiwalay ng salitang "foo" na sinusundan ng tatlong digit, ang sumusunod na regular na expression ay mag-parse ng data nang tama:

FS="foo"

Bilang ng mga patlang

Ang susunod na dalawang variable na titingnan natin ay karaniwang hindi sinadya upang sulatan, ngunit ginagamit upang basahin at makakuha ng kapaki-pakinabang na impormasyon tungkol sa input. Ang una sa mga ito ay ang NF variable, na tinatawag ding bilang ng mga field. Awkmatikong itinatakda ng Awk ang halaga ng variable na ito sa bilang ng mga field sa kasalukuyang tala. Maaari mong gamitin ang variable ng NF upang ipakita lamang ang ilang partikular na linya ng pag-input:

NF == 3 ( i-print ang "may tatlong field sa entry na ito: " $0 )

Siyempre, ang variable ng NF ay maaari ding gamitin sa mga conditional na pahayag, halimbawa:

( kung (NF > 2) ( i-print ang $1 " " $2 ":" $3 ) )

Record number

Ang isa pang maginhawang variable ay ang record number (NR). Palagi itong naglalaman ng bilang ng kasalukuyang tala (itinuturing ng awk na ang unang tala ay numero ng talaan 1). Sa ngayon ay nakipag-ayos kami input file, na naglalaman ng isang entry sa bawat linya. Sa ganitong mga sitwasyon, iuulat din ng NR ang kasalukuyang numero ng linya. Gayunpaman, kapag sinimulan naming pangasiwaan ang mga talaan ng maraming linya sa mga susunod na artikulo sa seryeng ito, hindi na ito mangyayari, kaya kailangan mong mag-ingat! Maaaring gamitin ang NR tulad ng variable ng NF sa output lamang ilang linya input:

(NR< 10) || (NR >100) ( i-print ang "Kami ay nasa record number 1-9 o 101 o higit pa")

Isa pang halimbawa:

( #skip header kung (NR > 10) ( i-print ang "ngayon ay dumating ang totoong impormasyon!" ) )

Nagbibigay ang Awk ng mga karagdagang variable na maaaring magamit para sa iba't ibang layunin. Titingnan natin ang mga variable na ito sa mga artikulo sa hinaharap. Dumating na kami sa dulo ng aming unang paggalugad ng awk. Sa mga susunod na artikulo sa serye, magpapakita ako ng mas advanced na functionality ng awk, at tatapusin namin ang seryeng ito gamit ang isang real-world na awk application. Pansamantala, kung gusto mong matuto nang higit pa, maaari mong tingnan ang mga mapagkukunang nakalista sa ibaba.