Kirjoittaja Aihe: awk ja sed ohjeistusta  (Luettu 3874 kertaa)

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
awk ja sed ohjeistusta
« : 17.06.13 - klo:06.31 »
Koodia: [Valitse]
Tämä sed-ohje on vielä keskeneräisempi kuin tuo awk-ohje seuraavassa.

Ohjelma sed muokkaa ohjelmallisesti sille annettua tekstiä.
- käsiteltävä teksti on usein tiedostoissa. jokaisen tiedoston rivit on numeroitu, sitä ei vain aina näytetä. Rivit numeroidaan
  järjestyksessä ykkösestä alkaen.
- käsiteltävä voidaan toimittaa sed:iin:
  1. sed määrittelyt tiedostonNimi  
  2. "tulostus jollain konstilla" | sed määrittelyt  
  tai kyllähän niitä kikkoja löytyy mutta ne selviävät kyllä kun semmoinen tulee eteen
- sed käy yksitellen läpi tiedoston kaikki rivit alkaen ykkösestö ja siitä järjestyksessä eteenpäin. sed:issä voidaan kuitenkin antaa
  osoitteita. osoitteet ovat joko rivinumeroita tai /teksti/. jos osoitteita on vain yksi niin muokkaaminen koskee vain sitä ja jos
  osoitteita on kaksi niin muokataan rivejä niiden välissä.
- jos toiminta juuttuu jonnekin kun ollaan sed:issä paina CNTRL-c.
- tiedoston teksti tulee näytölle jokatapaukseessa. Jos hjaluat muutoksen tallentuvan tiedostoon niin kirjoita: sed -i ...
- jos et halua tekstimuutoksen kirjoittuvan näytölle niin kirjoita: sed -n ...
- ihan rauhassa voi käskeä: sed 's/apu/apua/g'  sillä se ei päädy päättymättömään looppiin.
- mikäli peräkkäin on useampia sed:ejä niin sana sed kirjoitetaan vain kerran ja käskyt erotetaan kuten seraavassa esimerkissä:  
  sed -e '/^#/d' -e 's/#.*$//' # poistaa kommenttirivit ja kommentit pitemmältä
 
Esimerkkejä:
sed 's/mikä/miksi/g'                     # muuttaa jokaisen sanan:mikä muuttaminen sanaksi:miksi  
sed -i 's/mikä/miksi/g'                  # sama muutos, mutta tiedoston teksti muutetaan myös
sed -n 's/mikä/miksi/g'                  # sama muutos, mutta tiedoston teksti muutetaan niin ettei se tule näytölle
sed -ni 's/mikä/miksi/g'                 # sama muutos, mutta tiedoston teksti muutetaan myös eikä näytölle tule mitään
sed 's/.*mikä.*/miksi/g'                 # koko lauseen jossa sana:mikä on muuttaminen sanaksi:miksi  
sed '/baz/s/foo/bar/g'                   # tiedostossa tehdään muutokset vain riveillä joissa on jossain paikassa: baz  
sed '/baz/!s/foo/bar/g'                  # tiedostossa tehdään muutokset vain riveillä joissa ei ole jossain paikassa: baz
sed 's/^ *//g;s/ *$//g'                  # Poistaa välilyönnit tiedoston riveiltä edestä ja perästä. Tästä
                                         # näkee myös kuinka kaksi perättäistä sed:iä yhdistetään
sed  's/^ *//g'                          # poistaa välilyönnit tiedoston rivien alusta
sed "s/^.//g"                            # poistaa tiedoston jokaiselta riviltä ensimmäisen merkin, mikä se sitten onkin
sed -e '/^$/d                            # poitaa tiedoston tyhjät rivit
sed -i 6,66d                             # poistaa tiedoston rivit 6-66
sed -e '/^#/d' -e 's/#.*$//'             # poistaa kommenttirivit ja kommentit pitemmältä riveistä
sed '4!d'                                # tulosta ainoastaan tiedoston rivin 4 . Sama kuin sed -n '4p' tai: awk 'NR==4'
sed '8,12!d'                             # tulosta rivit 8-12
sed '8,12d'                              # tulostaa kaikkimmuut rivit paitsi 8-12
sed -i.bak 's/mikä/miksi/g'              # tee backup ennenkuin talletat muutokset
sed 's/:/\n/g' <<< $PATH                 # tämä tulostaa käyttöjärjestelmän polut kukin omalle riville  
sed "s:/old/direcory/:/new/directory/:"  # sedissä / toimii kenttien jakajana. Tällätavoin jakajaksi voi määrätä kaksoispisteen  
sed -n -e '1,/etsittävä ilmaisu/p'       # poista loput rivit löydettyään ilmoitetun lukumäärän etsittyä
sed 's/[![0-9]][0-9]:/"\ "&/g')          # &-merkin kohdalle tulee se tekstijono mikä [![0-9]][0-9]: määräämässä etsinnässä löytyi
sed 's/^ */"/g;s/ *$/"/g'                # lisää tiedoston jokaisen rivin alkuun lainausmerkki ja loppuun myös.
sed -e :a -e '/$/N;s/\n/ /;ta'           # tulostaa kaiken yhteen riviin
sed -e 's/^\(.*\) .*/\1/'                # poistaa viimeisen sanan jokaiselta riviltä    
sed -e '/^[<space><tab>]*$/d' somefile   # tulostaa tiedoston jättäen pois rivit jotka ovat pelkkää välilyöntia tai tabulaattoria
sed 'G'                                  # tulosta tiedosto lisäten tyhjän rivin jokaisen tekstirivin perään
sed -n '1!G;h;$p'                        # tulosta rivit käänteisessä järjestyksessä. Käskyssä käsitellään buffereita
sed -e '/./{H;$!d;}' -e 'x;/hakusana/!d' # tulosta jokainen kappale jossa on määriteltävä-hakusana
sed  '/kortti/alisätty_rivi'             # lisää rivi jolla lukee: lisätty_rivi jokaisen rivin jälkeen jolla lukee jossain kortti

sed -e 's/'$(echo "octal-value")'/replace-word/g' # kontrollimerkkien poistaminen
sed 's/mikä/miksi/g' tiedosto1 > tiedosto2        # lukee tiedosto1:stä, tekee muutokset ja kirjoittaa tiedosto2:een
sed 's/^./tekstiä /g'                             # kirjoittaa jokaisette ei-tyhjälle riville sanan: tekstiä
                                                    ja perään kirjoittaa sen tekstin joka rivillä ennen oli


echo abcd1eeee | sed 's/\([a-z]*\).*/\1/'                     # tulostaa abcd ja jättää ensimmäisen numeron ja sen jälkeiset pois
echo "eka toka kolmas" | sed 's/\([[:graph:]]*\).*/\1/' # tulostaa eka ja jättää loput sanat pois.
echo "1eka2 toka kolmas" | sed 's/\([[:graph:]]*\) \([[:graph:]]*\)/\2 \1/' # vaihtaa ensimmäisen ja toisen sanan

tiedostojärjestemän osassa kaikissa tiedostoissa sanan muuttaminen toiseksi:
find tiedostojärjestelmän_osa -type f -exec sed -i "s/mikä/miksi/g" {} \;

Koodia: [Valitse]
Grep käy sille annetun tekstin läpi rivi kerrallaan järjestyksessä alusta loppuun ja tulostaa näytölle kaikki ne rivit joilta etsitty löytyy.
Grep on yleensä määrätty värittämään hakutermin tulostuksensa jokaisella rivillä. Jos näin ei ole voi kirjooittaa grep-käskyn perään:
--color=always. Tai jos et halua väriä niin kirjoita grepin jälkeen: --color=none

Etsittävä voidaan antaa grep:ille kahdella keinolla:
1. tulosta_etsittävä_teksti_jotenkin | grep mitenkä_etsitään      
2. grep mitenkä_etsitään  sen_tiedoston_nimi_josta_etsitään  
- siis yksinkertainen haku on muotoa: echo "hhh 58 jjjj" | grep 58       tai: grep "kortti" tiedosto
- BASH:kin yrittää tulkita tuon mitenkä_etsitään ja joskus se ei ole toivottavaa. Tältä tulkinnalta voi suojautua kirjoittamalla
  'mitenkä_etsitään'. Joskus kuitenkin BASH:n toiminta on toivottavaa. Silloin kirjoitetaan: "mitenkä_etsitään"  .  
**
Grep tuntee ennaltamäärätyn merkkin, jossa merkki kuuluu johonki seuraavista ryhmistä:
[[:alnum:]]->[[A-Za-z0-9]]      [[:alpha:]]->[A-Za-z]         [[:blank:]]->välilyönti tai TAB   [[:cntrl:]]->jokin kontrollimerkki    
[[:digit:]]->[0-9]              [[:graph:]]->ASCII 33 - 126   [[:lower:]]->[a-z]                [[:print:]]->ASCII 32 - 126 ja välilyönti      
[[:space:]]->välilyönti ja TAB  [[:upper:]]->[A-Z]            [[:xdigit:]]->[0-9A-Fa-f]        
- skandit taitaa olla mukana vaikei niistä puhutakaan; tämä näkyy käskystä: echo "AAAAAAAAAAAAAAAAAö" | grep [[:lower:]]
- joskus hyväksytään kaksois-sulun paikalla vain yksi sulku
**
Kun haettavassa sanassa on joku seuraavista niin se tulkitaan kuvatulla tavalla:
?                paikalla voi olla yksi merkki tai sitten ei
.*               paikalla voi olla mielivaltainen määrän merkkejä, ja sen paikalla ei välttämättä täydy olla merkkiä ollenkaan
+                paikalla voi olla mielivaltainen määrän merkkejä, ja sen paikalla täytyy olla vähintään yksi merkki
.                paikalla voi olla täsmälleen yksi merkki.
[abcde]          paikalla voi olla täsmälleen yksi mukanaolevista merkeistä
[^abcde]         paikalla voi olla mikähyvänsä muu merkki paitsi jonku esitetyistä merkeistä. Merkkiä ! voi käyttää ^ paikalla.
[a3][c5]         paikalla voi olla joku merkkiryhmistä  ac,a5,3c,35
-E haettava{n}   haettava kertautuu täsmälleen n-kertaa # tämä ja seuraavat 3 eivät toimi niin kuin ihminen ymmärtää vaan niin kuin kone ymmärtää
-E haettava{n,}  haettava kertautuu korkeintaan n-kertaa
-E haettava{n,m} haettava kertautuu jotakin n,m välillä
-E haettava{,m}  haettava kertautuu korkeintaan m-kertaa
\< ja \>         hakusana rajoittuu tyhjään (=joko välilyöntiin tai rivin alkuun/loppuun)
[asdfg]          hakusana on mikähyvansä merkeistä asdfg (se ei siis etsi koko sanaa. Kun etsitään sanaa niin jätetään sulut pois).
[a-g]            sama toisella tavalla
[^asdfg]         hakusana on mikähyvänsä muuta merkkiä kuin jotakin joukosta asdfg  . ! on sama kuin ^.
[[:digit:]]      hakusanaksi voi antaa minkähyvänsä ennaltamäärätyistä merkeistä; siis sillä paikalla on vain yksi merkki
                 esimerkiksi jos etsittävässä on kaksi numeroa niin periaatteessa se on: [[:digit:]][[:digit:]]
**
grepin kytkimistä (optiot):
Optioiden alku on grep-sanan jälkeisen välilyönnin jälkeinen miinusmerkki. Jos miinus on jossain muualla ei se ole merkki optioiden
alkamisesta. Optioita voidaan kirjoittaa vaikka kuinkamonta ja vain tuo yksi miinusmerkki tarvitaan; vaikka jos haluaa niin jokaisen
option eteen voi kirjoittaa <välilyönti>miinusmerkki. Joskus tarvitseekin kertoa grep:ille että "nyt ne optiot loppu". Tällöin viimeiseksi
optioksi kirjoitetaan e. Senjälkeistä käsitellään etsittävän määrityksenä vaikka se alkaisi miinusmerkillä.

Seuraavassa luettelo yleisimmistä optioista:
r  etsintäpaikka on kansio ja sieltä etsitään rekursiivisesti     s  ei tulosteta edes varoitusviestejä            
c  vain löytöjen lukumäärä tulostetaan                            v  poista hakutuloksista ne joissa etsitty on osana
h  tulostaa sen tekstirivin jolta etsitty löytyy                  w  oleta etsittävän alkuun ja loppuun \< ja \>      
l  tulostaa sen tiedoston nimen josta etsitty löytyy              n  tulostaa myös miltä riviltä etsitty löytyi    
i  etsittäessä ei huomioida kirjainkokoa                          m <luku>   lopeta luku osumien jälkeen  
F  etsitään kirjaimiltaan juuri sellaista mikä etsittäväksi määrättään                                
e  optiot on nyt kirjoitettu ja haettava seuraa vaikka se alkaisi miinus-merkillä
E  ota käyttöön laajennoksia, mm. \ ei tarvita; siis esimerkiksi kun etsit "placeholdereita" niin etsittävä on: grep -E {} mistä_etsittään
A <numero>  tai: -B <numero> tai: -C <numero>      tulosta <numero> riviä haetun rivin edestä, jäljestä yai molemminpuolin
**
ESIMERKKEJÄ:
grep "[0-9]\{5\}"                  # etsii yli viisinumeroista sanaa jonka jokainen merkki on 0-9
                                   # täsmälleen viisinumeroiset: grep "\<[0-9]\{5\}\>"
grep [![:lower:]]                  # etsii onko sanassa jossain ainakin yksi pieni kirjain
grep [a-c]-ajokortti               # etsii a-, b- ja c-ajokortit mutta ei muita ajokortteja
grep [\ e]grep                     # etsii grep:in ja egrep:in muttei muita grepejä
grep '^\..*\.$'                    # etsittävä alkaa pisteellä ja loppuu pisteeseen ja välissä on jotain tekstiä.
grep -E ^a\|^b                     # etsii rivit jotka alkavat a:lla tai b:llä
grep -E "a{2}"                     # etsittävässä täytyy olla peräkkäin vähintään 2 a:ta
grep -E -o ".{0,5}etsittävä.{0,5}" # tulostaa etsittävä:n edestä ja perästä korkeintaan 5 merkkiä, eikä kokoriviä
grep . tiedosto > tiedosto2        # kopioi tiedostosta tiedosto2:een jokaisen rivin jolla on tekstiä (=poistaa tiedosto:sta tyhjät rivit)
grep -C <riviluku> hakusana        # tulosta etsityn lisäksi edestä ja perästä riviluku riviä
grep -v "^#"                       # tulosta jättäen pois kommenttirivit
grep -e .doc -e .html              # grepin tai-funktio. Myös (.doc)|(.html) toimii.
grep '\<c...h\>'                   # etsii viisikirjaimisia sanoja jotka alkavat c:llä ja päättyvät h:hon. Esimerkki: grep '\<c...h\>' sanakirja
grep '[Ss]mug'                     # etsii kumpaakin sanoista: Smug ja smug
grep '"smug"'                   # etsii lainausmerkeussä olevaa sanaa "smug". Ilman lainausmerkkejä ei kelpaa.
grep -- --                         # etsi kahta tai useampaa -merkkiä
grep -o -b  "etsittävä" | awk -F: '{print $1}' # tulostaa etsittävän ensimmäisen merkin sijainti-numeron (=pos-käsky
grep -Eio '([[:alnum:]_.-]+@[[:alnum:]_.-]+?\.[[:alpha:].]{2,6})' # tarkista onko kyse msähköposti-osoitteesta



**
HUOMAUTUKSIA:

- jostain syystä kun etsii ilmaisua: -exec kirjoitetaan hakusana: \\-exec

- etsittäessä merkkijonoa jonka alku ja loppu tiedetään mutta siinä välissä olevaa ei tiedetä niin hakusana on: tekstialussa.*tekstiloppussa
  tekstialussa ja tekstilopussa saavat olla eri riveillä. Joskus täytyykin painottaa että niiden täytyy olla samalla rivillä joten hakusana
  onkin: -e tekstialussa -e tekstilopussa
 
- etsittäessä merkkiä jolla on erikoismerkitys niin sen eteen tulee \. Siis esimerkiksi kun etsitään sanaa $-arvo niin hakusana on: \$-arvo

- useimmat erikoismerkit menettävät erikoismerkityksensä merkkien []   tai: '' välissä

- jos hakusana on etsittävän rivin alussa kirjoitetaan hakusanan eteen ^ ja jos se on lopussa kirjoitetaan hakusanan perään $ .
  Siis ^$ on tyhjä rivi. Mikäli merkki ^ on jossain muualla on se tavallinen merkki.

- nuo haut siis etsivät tiedoston sisällöstä. Kun etsit tiedoston nimestä niin käsky on esimerkiksi: find /home | grep "haettava"

- jos haluaa etsiä kahta sanaa samassa haussa onnisttu se käskyllä: egrep -w 'sana1|sana2' tiedosto

- grepin tulostuksesta voi muodostaa loopin: for i in /etc/profile.d/*.sh ; do ....; done

- oletetaanpa että koti-kansiossasi on skripti, jossa on käytetty käskyä tr hyvin erikoisella tavalla. Et muista missä se on ja haluaisit
  löytää sen. Annettava käsky on: grep -r "\<tr" ~  . (= tr:n tulee olla joko rivin alussa tai sitä täytyy edeltää välilyönti) Jos tuon
  \< jättää pois niin tulee tosipaljon "vääriä"" löytöjä.

- grepin toimintaan voidaan vaikutaa BASH:in ympäristömuuttujilla.

- grep:iä voidaa käyttää skripteissä myös siten, että skriptintoimintaa muutetaan senmukaan löytääkö grep jotakin vaiko ei. Tätä toimintaa
  vastaava käsky on: [[ $( grep ... ) ]] && tee_jotain. Tässä on kylläkin sellainen vikamahdollisuus että jos onnistuu tekemän grepin niin
  että se tekee virheen niin käsky suoritetaan aina. Siis joissakin tosi-harvinaisissa tapauksissa virheet pitää suunnata tiedostoon tai
  tarkistaa ettei muuttujan $? arvo ole 2.
« Viimeksi muokattu: 11.07.13 - klo:11.59 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: awk ja sed ohjeistusta
« Vastaus #1 : 03.07.13 - klo:15.21 »
Koodia: [Valitse]
Awk:illa voi muodostaa pikavauhtia ohjelmia jotka ovat säällisen nopeitakin, sillä awk on vain kytkin joka suoritututtaa
kaiken toiminnan C-kielisisissä ohjelmissa. Tein pienen alkeis-oppaan yksirivisten awk:lauseiden käyttämisestä BASH-skriptissä:

- awk ei tee muutoksia editoitavaan, awk vain tulostaa.  
- uudelleenohjaus kyllä toimii normaalisti, joten tiedostoon voi kirjoittaa. Uudelleenohjaus toimii samoin kuin BASH:issa. Siihen tiedostoon
   josta lukee ei kuitenkaan voi kirjoittaa.
- käsiteltävät voidaan toimittaa awk:iin joko: awk .... TiedostonNimi     tai: "tulostus jollain konstilla" | awk ....
  Teoriassa ne ovat samanarvoisia keinoja, mutta tiedostoissa on usein monia rivejä jotka käsitellään awk:in rungossa mutta
  kun syöte on ei-matriisi-muuttuja niin sitä käsitellään yleensä BEGIN osassa eikä muita osia ole. Awk  muuten vaatii syötettä
  silloinkin kun se ei tee syötteellä mitään.
- käskyjen muotoja tai tarkkaa kyky-luetteloa ei kannata opetella enempää kuin senverran että tietää mikä on mahdollista,
  sillä  ohjelmoitaessa käskyt kopioidaan esimerkki-varastosta eikä juuri mitään kirjoiteta.
- kovat lainausmerkit kuuluvat awk:iin ja esimerkiksi tulosteissa käytetään pehmeitä lainausmerkkejä ( kova on ' ja pehmeä " ).

____________________________________________________________________________________________________________________________

Jokaisessa awk-lauseessa on teoriassa kolme osaa:

1. BEGIN joka suoritetaan kerran alussa. Jos BEGIN osassa ei ole suoritettavaa niin sen voi jättää pois. Mikäli awk:issa tehdään
   joku kertasuoritus, esimerkiksi lasketaan jotakin niin se suoritetaan BEGIN osassa ja muut osat jätetään pois.

2. Runko joka suoritetaan niin monta kertaa kuin käsiteltävässä on rivejä: siis awk:n runko on looppi jota ei täydy eikä voi
   määritellä. Runko on se awk jota normaalisti käytetään ja nuo BEGIN ja END jätetään pois.
   - rungon lauseet ovat tyypiltään: ehto-{toiminto} jossa toiminto suoritetaan mikäli ehto on tosi. Ehto-{toimintoja} voi olla
     useampiakin kaksoispilkulla erotettuina. Mutta yhteen ehtoon tulee vain yksi toiminto; useampiakin toimintoja voidaan ehtoon
     kyllä laittaa mutta ne täytyy silloin erottaa lohkoksi kaarisuluilla.
   - awk lukee sisäänmenonsa rivi kerrallaan ja jakaa toimiessaan laittaa sen jokaisen rivin jokaisen sanan omaan muuttujaansa.
     Näihin muuttujiin viitataan $1, $2, $3 ... . ja muuttuja $0 on koko lause. Siis kaikki ne vaihtuvat kun uutta lausetta
     aletaan käsittelemään. Samoin awk määrittelee uudet arvot sisäisille muuttujilleen aina käsiteltävän lauseen muuttuessa:
     FS, OFS, NF, NR, FNR, RS ja ORS
       - FS     mikä merkki jakaa sanat. Oletusarvo on välilyönti.
       - OFS    tämä arvo muuten asetetaan ohjelmassa ja se on se merkki joka jakaa sanoja tulosteessa, Oletusarvo on välilyönti
       - NF     kertoo montako sanaa on luettu.
       - FNR    kertoo kun on luettu monta tiedostoa mikä kussakin riviluku on
       - RS     kertoo mikä merkki jakaa lauseet sisääntulossa. Oletusarvo on rivinvaihto \n
       - ORS    kertoo millä merkillä tulostus-rivit jaetaan. Oletusarvo on rivinvaihto \n
       - ellei muuta mainita niin sanojen erottimena FS toimii välilyönti, mutta erottimeksi voidaan asettaa miksi hyvänsä
         käskyllä: -F<välimerkki>Hae

3. END joka suoritetaan kerran lopussa. Jos END osassa ei ole suoritettavaa niin sen voi jättää pois. Mutta jos END-osa on niin
   runko-osa täytyy myös olla, vaikka pelkkä numero 0.

   esimerkkejä BEGIN ja END-lohkojen käytöstä:
   - awk 'BEGIN { print "koneessa olevien imageiden lukumäärä:"} /menuentry/{n++} END {print n}' /boot/grub/grub.cfg
   - seq  21 | awk 'BEGIN {a=1; b=1} {b=b+1;a=a*b} END {print "kertoma: " a}'         # huomio että seg 21 on matriisi
   - awk 'BEGIN { while (count++<50) string=string "x"; print string }'               # tulostaa 50 x:ää
   - awk 'BEGIN{ count=1; do print "Tämä tulostuu ainakin kerran"; while(count!=1)}'  
____________________________________________________________________________________________________________________________

- Awk olettaa paljon siitä mikä jätetään mainitsematta. Määrää siis tai awk olettaa !
  Esimerkiksi käsky: awk 1 tiedosto       tulostaa tiedoston sillä 1 on aina tosi ja print suoritetaan kun muutakaan ei määrätä.
  Lauseessa ei myöskään ole mainintaa siitä mitä pitäisi tulostaa - mutta awk olettaa että haluat tulostaa käsittelyssä olevan
  rivin jos et määrää toisin. Ja käsky: awk '{ print $1 }' tiedosto     tulostaa tiedoston jokaisen rivin ensimmäisen kentän,
  sillä koska ehtoa ei ole niin awk olettaa että jokainen rivi täyttää ehdon.

- Kaikki mikä tapahtuu awk:issa unohdetaan kun awk:in suoritus lopppuu. Awk ei pysty asettamaan BASH:in muuttujia eikä BASH
  kykene asettamaan awk:in muuttujia. Mikäli haluaa käyttää awk:in muuttujia BASH:issa täytyy awk:n tulostaa ne ja BASH:in
  napata muuttujien arvot konstilla: muuttuja=$(awk .....) ja awk:iin päin muuttujat siirretään putkittamalla ne.
  Mutta awk kykenee käyttämään BASH:in muuttujia monellakin tavalla, esimerkiksi:
    - koe=12345 ; awk 'BEGIN { print '"$koe"'; }' # tällä konstilla piisaa rajoituksia.
    - arvo="4.58"; echo -n "" | awk -v arvo="$arvo" 'BEGIN { print arvo }'
    - haettava="menuentry"; awk "/$haettava/ "'{ osumia++ } END { print "imageiden lukumäärä: " osumia }' /boot/grub/grub.cfg  
    - awk 'BEGIN {  printf "Moikka %s" ,ENVIRON["USER"] }'
    - export a="onnistuu se näinkin"; awk 'BEGIN {  printf "%s" ,ENVIRON["a"] }'
    - export tunnus=$(awk '/ Varaustunnus:/{print $2}' tiedosto); echo $tunnus

- awk:n sisäiset muuttujat: FS, OFS, NF, NR, FNR, RS ja ORS . Esimerkkejä:
   - awk '{ if (NF > 0) printf("%s\n", $0); }'          # tiedoston tyhjien rivien poistaminen
   - awk 'NF { $0=++ a " : " $0 }; { print }'           # tulostaa tiedoston rivien eteen: <rivinumero>:
   - awk '{ total = total + NF } END { print total }'   # tulostaa tiedoston sanojen lukumäärä.
   - awk '{if (NR % 2 == 1) print $0}'                  # tulostaa vain parittomat rivit
   - awk 'NR >= 3 && NR <= 6'                           # tulostaa rivit 3-6
   - awk 'BEGIN { ORS="\n\n" }; 1'                                                # tulostaa tiedoston rivien väliin tyhjän rivin
   - awk '1; { print "" }'                                                        # sama toisella tavalla.
   - awk 'BEGIN { FS=" ";OFS="#" } { if ($1==1) print $1,$2 }' ~/testResults.dat  # tulostuu: 1#2 kun luettavassa on rivi 1 2
     - print $1,$2 pitää olla pilkun kanssa; print yksinkin tulostaa kaiken, mutta välieroitin ei muutu - print $0 ei myöskään toimi
   - awk 'END {print NR}' tiedosto                                                # tulostaa tiedoston rivien lukumäärän
   - awk '{if (NR % 2 == 1) print $0}'                                            # tulostaa vain parittomat rivit  
   - awk -F : '{print $1}' /etc/passwd                 # tulostaa käyttäjien nimet (suurin osa on käyttöjärjestelmän ohjelmia)
   - echo "1=2 3" | awk -F "=| " {'print $1, $2, $3'}  # voidaan määrätä useampikin kentänjako |-funktiolla.
                                                       # Käskyssä {'print $1, $2, $3'} pilkut tulostavat OFS:n arvon.

- awk:in vertailuoperaattorit ovat: == , != , < , > , <= , >= , ?: ~ ja !~  Esimerkiksi:
   - awk -F':' '$6 ~ /home/ && $3 >= 1000 { print $1 }' /etc/passwd  # listaus tietokoneen käyttäjistä. Selväkielisenä tämä on:
     Jaa tiedosto /etc/passwd kenttiin joiden rajana on merkki : . Kun kentässä 6 on osana sana home niin mikäli kentän 3 arvo
     on yli 1000 niin tulosta kenttä 1.          
   - tuo ?: on ehdollinen ehto:  ehto1 ? ehto2 : ehto3  
     Mikäli ehto2 on tosi toimitaan jatkossa ehto2:n mukaan mutta jos se ei ole tosi niin toimitaan ehto3:n mukaisesti.  
   - verrattavalla sanalla voi olla samanlaisia lisämääreitä kuin grep:illä: $ ^ . [....] [^....] | (....) * + ? /

- awk tuntemaa matematiikkaa: + ,-, *, /, %, välilyönti, **, int, log, sqrt, exp, atan2(m,n), sin, cos, tan, rand, srand
   - luontaista suoritusjärjestystä voi muuttaa suluilla.
   - matikka on kaksois-tarkkuutta (noin 22 numeroa)
   - awk tuntee kokonaisluvut, desimaaliluvut, assosiatiiviset matriisit ja tekstijonot. Myös eksponentti-esitys tunnetaan.
   - awk:in muuttujat ovat tyypittömiä. Operaatiot ++ ja -- tunnetaan. && on ja-toiminto, || on tai-toiminto ja ! on negaatio.
   - Bitti-operaatioista tunnetaan and, or, xor, lshift, rshift ja compl. And, or ja xor voivat ottaa useampiakin lukuja.
   - välilyöntioperaattori liittää yhteen eri puolillaann olevat. Siten 1+2*3 4; on arvoltaan 74. Esimerkkejä:
     - awk '{sum+=$1; sumsq+=$1*$1} END {print sqrt(sumsq/NR - (sum/NR)^2)}'    # ensimmäisen sarakkeen normaalipoikkeama
     - awk 'BEGIN { print atan2(30,45); }'                                      # palauttaa y/x arctangentin radiaaneissa.
     - seq  21 | awk 'BEGIN {a=1; b=1} {b=b+1;a=a*b} END {print "kertoma: " a}' # kertoma. Huomio että seg 21 on matriisi

- merkkijonon käsittely-funktiot: index, length, match, split, sprintf, sub, gsub, substr, tolower, toupper . Esimerkiksi:    
  - echo ~/kansio1/kansio2/tämä muutetaan suurille | awk -F"/"  '{ $NF=toupper($NF); print }' OFS="/"
  - awk 'BEGIN {var = sprintf("[%8.3f]",3.141592654); print var}'       # siis tämä on toiminto "printtaa stringiin"
  - echo "kattokassinen" | awk '{gsub(/ka/,"ki");print}'                # tulostaa: kittokissinen (gsub=global sub)
  - awk '{ if (length($0) > max) max = length($0) } END { print max }'  # tulostaa tiedoston pisimmän rivin pituuden
  - awk '{print substr($0, index($0,$N))}'                              # tulosta N-palasesta eteenpäin
  - awk 'length($0)!=12 {print}' your_file_name                         # tulosta rivit jotka eivät ole 12 merkkiä pitkiä
  - awk -F':' '{split($0,a,":"); for (i=1; i<=NF; i++) if (a[i]) print i,"   ",a[i]}' /etc/passwd
    - siis splitin jakaja ei määrää awk:in jakajaa

- I/O:n käsittely-funktiot: close, system

- awk tuntee myös ehtolauseet if, if-then ja if-else-then. Awk tuntee myös rakenteen ?: joka on itseasiassa if-else rakenne.
   - esimerkkejä:
   - awk '{ if (NF > 0) printf("%s\n", $0); }'                    # tiedoston tulostaminen tyhjät rivit poistettuina
   - awk '{if (NR % 2 == 0) print $0; else print "pariton rivi"}' # tulostaa sanan pariton tai rivit jotka ovat parillisia.

- awk tuntee myos kierroslaskurin. Tunnetaan for, until, while ja do....while loopit. Myös break, continue ja exit tunnetaan.
  Kierroslaskurin arvoksi jää sen viimeinen arvo kun kierrokset on tehty tai viimeinen arvo ennen break ja continue lauseita.
  Esimerkkejä:


  - awk '{ for (i = 0; i <= NF; i++); { printf "("%s ", i);}; printf("\n"); }'  # rivien sanojen luku



awk tuntee printf:n muotoiluineen ja sen voi kirjoittaa print:in paikalle aina. Muotoilu-määreet ovat:
%c Tulostaa ASCII-numeroa vastaavan merkin. Esimerkiksi awk 'BEGIN {printf "%c", 65}' tulostaa "A"
%d Tulostaa kokonaisluvun
%i Tulostaa kokonaisluvun
%e Tulostaa luvun halutussa eksponenttimuodossa. Esimerkiksi printf "%4.3e", 1950 tulostaa: 1.950e+03
%f Tulostaa desimaaliluvun
%g Tulostaa luvun joko desimaali- tai eksponenttimuodossa sen mukaan, kummassa tarvitaan vähemmän merkkejä
%o Tulostaa etumerkittömän oktaaliluvun
%s Tulostaa merkkijonon
%x Tulostaa etumerkittömän heksaluvun
%X Tulostaa etumerkittömän heksaluvun käyttäen desimaaliluvuille 10-15 isoja kirjaimia
- print tulostaa ilmanmuuta tulostettavan perään rivinvaihdon mutta printf ei

awk tuntee muuttujan ARGV jonka jäsen ARGV[1] on luetun tiedoston täysi nimi. Siitä esimerkki ja muutakin kokeilua:
Tiedostossa ~/taulukko on teksti:
1 2 3
4 5 6
7 8 9
- ja tarkoituksena olisi tulostaa taulukon arvot sekä sarake- ja rivisummat, muotoilla senverran että siitä saa selvää ja tulostaa
  mistä tiedostosta arvot ovat:
  awk 'BEGIN {print "arvot ovat tiedostosta: "ARGV[1]}; {rivisumma1+=$1;rivisumma2+=$2;rivisumma3+=$3;printf "%s %s %s     sarakesumma=
  %d\n",$1,$2,$3,$1+$2+$3} END {printf "%s %d %d %d %s","\nrivisummat:\n",rivisumma1,rivisumma2,rivisumma3,"\n\n"}' ~/taulukko



Sekalaista:
awk '/foo/'                                                   # tulostaa rivit joilta löytyy foo                    
awk '/kortti/,EOF'                                            # tulosta tiedosto riviltä jossa on jossakin sana kortti loppuun asti
awk '/foo/ && /bar/'                                          # tulostaa rivit joilta löytyy foo tai bar jossain järjestyksessä
awk '/foo/ && !/bar/'                                         # tulostaa rivit joilta löytyy bar mutta ei foo
awk '/foo/ || /bar/'                                          # tulostaa rivit joilta löytyy joko bar tai foo
awk '/foo/,/bar/'                                             # tulostaa rivit riviltä jolta löytyy foo riville jolta löytyy bar.
awk 'BEGIN { print strftime() }'                              # tulostaa saman kuin BASH:in date
awk 'BEGIN { print systime() }'                               # tulostaa sekunnit siitä unixin alkuhetkestä
awk '{printf("%d\n",$1 + 0.5)}'                               # pyöristys; toimii sekä positiivisilla- että negatiivisilla luvuilla
awk '{if ($1 % 2 == 0) print $1 " on parillinen" ;else print $1 " on pariton"}'
awk '{$1=""; print}'                                          # tulosta kaikki muu paitsi sarake 1
awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}'                # poistaa ByteOrderMark:in; esimerkiksi notepad lisää sen.
                                                              # Käsky ei tee mitään jos BOM:ia ei ole. Tämä BOM on UTF-8:ssa
awk '!($0 in array) { array[$0]; print }'                     # tulostaa tiedoston, mutta samanlaisista riveistä vain ensimmäisen
awk '!a[$0]++'                                                # sama toisella tavalla
 

awk osaa lukea näppäimiäkin:
awk 'BEGIN {print "kerropa ikäsi:"; getline ika < "-"; print "ensi vuonna olet: " ika + 1 }'

- tuntee awk funktiotkin, mutta ne kuuluvat varsinaiseen awk-skriptiin, ei tämmöiseen yksiriviseen. Toiminta kuten BASHissa.
- BASH:in funktioitakin voi käyttää, mutta epäluotettava viritys tämä on:
 echo -n "jotakin" | awk '{ tmp="echo -n " $1 " | openssl md5"; tmp | getline a; print a}'  
« Viimeksi muokattu: 25.07.13 - klo:06.05 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: awk ja sed ohjeistusta
« Vastaus #2 : 09.07.13 - klo:21.05 »
Koodia: [Valitse]
Find on niin monipuolinen ettei sitä kannata selittää tavallisin keinoin, vaan aloittaa esimerkein:

find ~  # listaa kotikansion rekursiivisesti. Listauksessa on niin kansiot kuin tiedostotkin ja kaikki esitetään täydellisine polkuineen.

find ~ -type f  # listaa ainoastaan tiedostot 
find ~ -type d  # listaa ainoastaan kansiot   

find ~ -maxdepth 1 -type f # maxdepth määrää listaamaan tiedostot vain niin monelta tasolta kuin sen numero osoittaa.
find ~ -size 0             # listaa nollakokoiset tiedostot. Linuxissa on muuten paljon nollakokoisia tiedostoja jotka ovat Linuxin
                           # toiminnalle välttämättömiä.
find ~ -name *.txt         # listaa vain *.txt nimiset tiedostot. Listaa muuten kansiotkin, mutta harvemmin kansion nimessä on peräliite .txt.
find ~ -name *~ -delete    # poistaa backup-tiedostot kaikkialta kotikansiosta. Mietipä kannattaako käskyä kokeilla.
find /etc/rc3.d | sort -g  # lista käyttöjärjestelmän palveluista; luepa README

find ~ -maxdepth 1 -type f -print0               # tulostaa kaikki yhteen jonoon; tulostettuja erottaa vain näkymätön nolla-merkki
find ~ -type f -print0 | xargs -0 komento        # jota hyödynnetään näin - tiedostojen nimissä voi silloin olla välilyöntejä ym. kummallista
 
find ~ -maxdepth 1 -type f -exec echo '{}' \;    # Tarkoitus on esitellä käsky -exec. Echo:n paikalle voi laittaa minkä käskyn tahansa
                                                 # tuo '{}' kuvaa find:in löytämää tiedostonimien-joukkoa; siitä poimitaan käsiteltävät
                                                 # järjestyksessä yksikerrallaan. Muuten kaikki käskyt laittavat tulosteensa tuonne {}
                                                 # "paikanpitäjään". Esimerkiksi: ls . | xargs -i echo {}
find ~ -maxdepth 1 -type f -exec echo '{}' +     # tehokkaampi muoto, mutta monet koneet eivät hyväksy sitä

find . -mtime 0                                  # etsii tiedostot joita on muutettu 0-24 tuntia sitten
find . -mtime -1                                 # etsii tiedostot joita on muutettu 0-24 tuntia sitten
find . -mtime 1                                  # etsii tiedostot joita on muutettu 24-48 tuntia sitten
find . -mtime +1                                 # etsii tiedostot joita on muutettu yli 48 tuntia sitten
find . -mmin +5 -mmin -10                        # etsii tiedostot joita on muutettu välillä 6-9 minuuttia sitten

find ~ -perm 777                                 # etsi tiedostot joille on annettu 777 käyttöoikeudet
find ~ -type f -exec chmod -x {} \;              # poista suoritusoikeus kaikilta tiedostoilta
find ~ -uid 1000                                 # etsi käyttäjän 1000 tiedostot
find ~ user petteri                              # etsi käyttäjän petteri tiedostot
find ~ -fprint ~/foo                             # kirjoita löytyneet tiedostoon ~/foo
sudo find / -type f -iname "*Trash"              # etsi mistä kaikkialta löytyy roskiksia - myös pääkäyttäjän roskikset tulostuu, samoinkuin
                                                 # roskikset muistitikulta ym.
                                                 
                                                 # tiedoston nimessä voi olla on merkki /. Sellainen tiedosto on kylläkin käyttökelvoton eikä
                                                 # sen poistaminenkaan onnistu ihan noinvain. Inodet saa listattua käskyllä ls -i 
find /-xdev -inum inode-numero                   # etsii missä se inode sijaitsee. Tuo xdev rajoittaa haun omaan tiedostojärjestelmään.
find . -inum inode-numero -exec rm {} \;         # tiedoston tai koko kansion poistaminen inoden perusteella
 
find -name \*conf > ~/asetustiedostot            # tee lista asetustiedostoista tiedostoon: ~/asetustiedostot
find . -name "*.file" -type f -print | xargs file | grep ASCII | cut -d: -f1  # tiedostolistaus jättäen pois binääritiedostot
find . -type f -print0 | xargs -0 du -h | sort -hr | head -20                 # listaa kaksikymmentä isointa tiedostoa ja kertoo niiden koot.

find ~ -type f -exec md5sum '{}' ';' | sort | uniq --all-repeated=separate -w 33 | cut -c 35-  # etsi tiedostot joilla on sama sisältö
find mistä_kansiosta_eteenpäin_muutetaan -type f -exec sed -i "s/mikä/miksi/g" {} \; # muuta sana toiseksi polun kaikissa tiedostoissa
sudo find / ! -path /proc\* ! -path /run/user\* \( -nouser -o -nogroup  \)           # etsii tiedostot jotka eivät kuulu kenellekään. Jos
                                                                                       niitä on on jossakin ongelmia, joskus pahojakin.

 
- listauksissa on usein sellaista joka vain sekoittaa ja silloin kannattaakin käyttää suodatusta:
  Piilotiedostojen poistaminen listauksesta:              | grep -v /.          (piste kuuluu käskyyn)
  listaus yksinomaan nimistä joissa on kontrollimerkkejä: | grep *[[:cntrl:]]*  (jos konrollimerkkejä ei saa olla niin:[^[:cntrl:]])
- ellei jotain määrätä niin find on: lettaa eikä oletus ole aina miellyttävä. Esimerkiksi ellei ole määrättystä-lähtien etsitään niin find
  aloittaa etsimisen siitä kansiosta jossa ollaan. Ihan hyvä että toimii aina, mutta valitettavasti kun muulloin tulosteessa on koko polku
  niin oletushaku tulostaa polun alun muodossa ./ . Ja jos mitään suoritettava ei ole määrätty niin find olettaa että halutaan suorittaa
  tulostus elikkä print - mutta jos määrätään joku  muu toimi niin print jää pois ellei erikseen print:tiä määrätä. Tai tavallisesti
  tulostetaan sekä tiedostot että kansiot - mutta jos määrätään tulostamaan tiedostot niin kansioita ei tulosteta ellei erikseen määrätä.
- find löytää monesti niinpaljon asioita että tulostus tuntuu jatkuvan ikuisesti. Tulostuksen saa loppumaan kun painaa ctrl-c jolloin
  palataan päätteeseen - senkertaisen find:in tulokset häviävät mutta muuta ei tapahdu.
- Linux on levykäyttöjärjestelmä; nykyään se on vain nimi, mutta aikoinaan käytäntö. Mutta se kertoo miksi find-ohjelma on edelleenkin tärkeä.
-

Kaiken voi tehdä monella tavalla, eikä etukäteen voi tietää mikä tapa on tilanteeseen paras. Esimerkiksi kolme käskyä jotka tekee samaa asiaa,
ja varmasti on miljoona muutakin tapaa:
find / -name core | xargs /bin/rm -f
find / -name core -exec /bin/rm -f '{}' \;
find / -name core -delete                 
« Viimeksi muokattu: 10.07.13 - klo:17.28 kirjoittanut petteriIII »