6. gyakorlat

Szabályos kifejezések

  • Mire jó?
    Stringek rugalmas megadására, szöveg kereső, helyettesítő programokban. Mintákat (pattern) adhatunk meg, és egy-egy mintára való illeszkedéstől függően csinálhatunk vmit az adott szövegrésszel
  • Emlékeztető:
    cp /usr/share/pictures/*.xmp ~/pics/
    Ez NEM szabályos kifejezés
  • Hol használhatjuk?
    grep, egrep, sed, awk és újabban bash kifejezésekben "[[ ]]"
  • Hol nem működnek?
    • fgrep
    • filnevek megadásánál (hasonlít a joker karakterekre)
    • case elágazásnál (szintén csak "joker szabályok" használhatóak)
    • test (vagy [ ]) feltételeknél

Milyen építőelemek (atom) vannak?

cEgy darab NEM SPECIÁLIS karakter
.Egyetlen tetszőleges karakter
^Sor eleje (egész pontosan a sor elején lévő üres string illeszkedik rá)
$Sor vége (a sor végén lévő üres string illeszkedik rá)
\cHa a "c" karakternek vmilyen speciális jelentése van, a \ jel kikapcsolja ezt a speciális jelentést
[karakterek]A felsorolt karakterek bármelyike (de csak 1) illeszkedik rá
[^karakterek]A NEM felsorolt karakterek bármelyike
[c1-c2]c1 és c2 közötti karakterek bármelyike
Egy zárójelbe tett reguláris kifejezés

FONTOS: a [ ]-ek belsejében a speciális jelek elvesztik a különleges jelentésüket!

Milyen jelentésmódosító jelek vannak?

atom* 0 vagy többszöri ismétlődés
atom+ Egy vagy többszöri ismétlődés
atom? 0 vagy egyszeri ismétlődés
atom{m}Pontosan m-szeri ismétlődés
atom{m,}Legalább m-szeri ismétlődés
atom{m,n}Legalább m-szeri, de legfeljebb n-szeri ismétlődés

Speciális jelek - összefoglálás

Két csoportra oszthatjuk azokat a jeleket, melyek valamilyen speciális jelentéssel bírnak a szabályos kifejezésekben. Az első csoportba tartoznak azok a spec. jelek, melyek különleges jelentése alapértelmezésben be van kapcsolva. Míg a másik csoportba tartozó jelek speciális jelenzésel alapértelmezésben ki van kapcsolva.

  • * , . , [ , ] , \ , ^ , $
  • { , } , ( , ), | , + , ?

FONTOS:A fenti csoportosítás csak az úgynevezett alap szabályos kifejezések (basic regular expression) esetében érvényesek. Az ún. kiterjesztett szab. kifejezések (extended reg. expr.) esetében minden speciális jel különleges jelentéses be van kapcsolva

grep

Egy kereső program, mely fileokban (vagy az standard inputjára érkező adatokban) képes keresni bizonyos tulajdonságú sorokat. Ezeket a "tulajdonságokat" adhatjuk meg szabályos kifejezésekkel.

A grep-en kívül használható még az fgrep (nem kezel szab. kif.-eket) és az egrep (kiterjesztett. szab. kif.-ek) is.

Példák

cat f1 | grep "36" cat f1 | grep 36 grep "36" f1 cat f1 | grep "alma" # Ezekben a példákban használható lett volna az fgrep is

cat f1 | grep "a*" # itt mást jelent a * , mint jokereknél !! cat f1 | grep 'a*' # ugyanaz, mint a " " esetében cat f1 | grep 'a\*' # 'a*'-ot keres cat f1 | grep a* # HIBÁS, mert a *-ot "megeszi" a shell cat f1 | fgrep "a*" # 'a*'-ot keres!!

ls -la | grep "^d" | wc -l ls -la | grep "gyak1$" ls -la | grep "gyak1.txt$" ls -la | grep "gyak1\.txt$" cat f1 | grep "^a\*"

cat f1 | grep "a.$" cat f1 | grep "^.a" cat f1 | grep "..." # olyan sorok, melyek legalább 3 karakterből állnak cat f1 | grep "\.$" # sorvégi . karakter cat f1 | grep "\.\.\." # ... -t tartalmazó sorok

cat f1 | grep "[abc]" # a megadott karakterek bármelyike cat f1 | grep "^[abc]" # itt a ^ a sor elejét jelenti cat f1 | grep "[^abc]" # itt pedig tagadást cat f1 | grep "[0-9]" cat f1 | grep "[a-zA-Z]" cat f1 | grep "[A-Z][a-z]" cat f1 | grep "[^0-9][0-9]" cat f1 | grep "[]abc]" # Ha megát a ']' jelet is bele akarjuk tenni a tartományba, # akkor az első helyen kell állnia cat f1 | grep "[^]abc]" cat f1 | grep "[A-Za-z_-]" # Ha a '-' jelet is bele akarjuk venni, # akkor vagy az első vagy az utolsó helyen kell állnia cat f1 | grep "[-+]" # Itt a '-' az első helyen áll # a '+' pedig egyszerű karakternek számít, mert [ ] belsejében van! cat f1 | grep "[.*]" # Vagy '.' vagy '*' karakter cat f1 | fgrep "[.*]" # Olyan sorok, amelyekben szerepel a '[.*]' string

cat f1 | grep "^a*" # a * előtt lévő kifejezés akárhány (0 is) előfordulása cat f1 | grep "^a.*" cat f1 | grep "[0-9].*"

cat f1 | grep "^a\+" # az előtte álló kifejezés legalább egyszeri előfordulása cat f1 | grep "^a+" # ez így soreleji 'a+'-t keres cat f1 | grep "^a\?" #Vigyázzunk! cat f1 | egrep "^a\+" cat f1 | egrep "^a+"

cat f1 | grep "\(ab\)\+" cat f1 | egrep "(ab)+" cat f1 | grep "\([a-z][0-9]\)*"

cat f1 | grep "\.\{3\}" # PONTOSAN 3 egymástkövető pontot tartalmazó sorok cat f1 | grep "\.\{4,\}" # LEGALÁBB 4 egymástkövető pont cat f1 | grep "[0-9]\{3,7\} # LEGALÁBB 3 de LEGFELJEBB 4 számjegy

cat f1 | egrep "asztal(on|ban|hoz|nak)" # csak az egrep tudja

jel=`head -n1 f.txt | cut -c1` who | cut -d' ' -f1 | grep "^$jel.*a$"

cat f1 | grep -- "-\?28" # Illeszkedik rá a 28 és a -28 cat f1 | grep "\-\?28" # Ugyanaz, csak máshogy megoldva a '-' probléma cat f1 | grep -- "-\?[0-9]\+" # Pozitív és negatív egész számok cat f1 | grep "\-\?[0-9]\+" cat f1 | grep "[12]-[0-9]{6}-[0-9]{4}" cat f1 | grep "[12]-[0-9]\{6\}-[0-9]\{4\}"

cat f1 | grep "\\" # rossz!! cat f1 | grep '\\' # jó cat f1 | grep "^\([a-z]\)\1" cat f1 | grep "\([0-9]\)\1$"

Egyéb lehetőségek

POSIX Character Classes [[:class:]]
[[:alnum:]] matches alphabetic or numeric characters. This is equivalent to A-Za-z0-9.
[[:alpha:]] matches alphabetic characters. This is equivalent to A-Za-z.
[[:blank:]] matches a space or a tab.
[[:cntrl:]] matches control characters.
[[:digit:]] matches (decimal) digits. This is equivalent to 0-9.
[[:graph:]] (graphic printable characters). Matches characters in the range of ASCII 33 - 126. This is the same as [:print:], below, but excluding the space character.
[[:lower:]] matches lowercase alphabetic characters. This is equivalent to a-z.
[[:print:]] (printable characters). Matches characters in the range of ASCII 32 - 126. This is the same as [:graph:], above, but adding the space character.
[[:space:]] matches whitespace characters (space and horizontal tab).
[[:upper:]] matches uppercase alphabetic characters. This is equivalent to A-Z.
[[:xdigit:]] matches hexadecimal digits. This is equivalent to 0-9A-Fa-f.

Egy kidolgozott példa

Részlet a Unix/Linux héjprogramozás c. könyvből

grep parancsról részletesen - kapcsolók

  • -num: Az illeszkedést mutató sorok környezetükkel együtt kerülnek az stdout-ra, azaz nem csak az illeszkedő sort írja ki, hanem az adott sor előtti és utáni num db sort is. DE: egy sor csak egyszer szerepel, azaz ha átfedések vannak, akkor is egy sor max. egyszer kerül kiírásra
  • -A num: Az illeszkedést mutató sorok UTÁNI num db sor is kiírodik
  • -B num: Az illeszkedést mutató sorok ELŐTTI num db sor is kinyomtatásra kerül
  • -c: Elhagyja a szokásos kimenetet, ehelyett az illeszkedést mutató sorok számát írja ki, minden file esetére
  • -e minta: Megmondjuk neki, hogy most minta(pattern) jön, pl hasznos ha '-' jellel kezdődik a mintánk
  • -f fájl: A mintát a megadott file-ból veszi
  • -h: Több fileból való kereséskor elhagyja a kimenetről a filnevek sor eleji kiírását
  • -i: Nem különbözteti meg a kis -és nagybetűket
  • -L: Elhagyja a szokásos kimenetet és csak azokat a filenekevet írja ki, amelyekben NEM volt(ak) illeszkedő sor(ok)
  • -l: Elhagyja a szokásos kimenetet és csak azokat a filenekevet írja ki, amelyekben volt(ak) illeszkedő sor(ok)
  • -v: Megfordítja az illeszkedés értelmét: azok a sorok kerülnek listázásra, melyek NEM illeszkednek a mintára
  • -w: Csak azokat a sorokat választja ki, amelyekben az illeszkedés teljes szavakból származik
  • -x: Csak teljes sorokkal való illeszkedést vizsgál

sed (Stream EDitor)

  • Tulajdonképpen egy nem interaktív programozható szövegszerkesztő/manipuláló program
  • Vagy paraméterként várja a feldolgozandó file-t vagy az stdin-ről olvas (mint a grep)
  • Ez is sor alapú, mint a grep, azaz egyszerre egy sort olvas be, és ezen hajtja végre a megadott műveleteket

A legegyszerűbb parancs: p (print)

cat f1 | sed 'p' cat f1 | sed '5p' cat f1 | sed -n '5p' cat f1 | sed -n '2,5p' # 2-től az 5-ig sorig!

Törlés: d (delete)

cat f1 | sed '3d' cat f1 | sed '3,5d'

Csere 0.1: y (transform)

echo "abcdabcdXYZ" | sed 'y/abcd/xyzk/' # eredmény: xyzkxyzkXYZ

Tulajdonképpen ugyanazt csinálja, mint a tr nevű unix parancs, azonban van egy lényeges különbség: sed-nél, ha az y-t használjuk nem adhatunk meg tartományokat ([a-z]), míg tr-nél igen.

Csere: s (substitute)

Szintaxis

sed 's/mit/mire/módosító'

Mi történik?

A sed végignézi az összes sort (egyenként), és ha talál olyan szövegrészt, ami illeszkedik a 'mit' mintára, lecseréli a 'mire' mintának megfelelő szövegre. Ha nem adunk meg 'módosító'-t, akkor hibába van több olyan szövegrész is a sorban, amire illeszkedit a 'mit', csak az elsőt cseréli!

sed 's/mit/mire/N' -> Csak az N-edik előfordulást cseréli (minden sorban újrakezdi a számolást)
sed 's/mit/mire/g' -> Az összes előfordulást cserélni

echo "1234567abcde" | sed "s/[a-z]/X/" echo "1234567abcde" | sed "s/[a-z]\+/X/g" # a várt eredmény: 1234567XXXXX # a valós: 1234567X echo "1234567abcde" | sed "s/[a-z]*/X/g" # X1X2X3X4X5X6X7X echo "1234567abcde" | sed "s/.*/XXX&YYY/" # XXX1234567abcdeYYY echo "abc1234def" | sed "s/[a-z]\+/X&Y/" # XabcY1234def echo "abc1234def" | sed "s/[a-z]\+/X&Y/g" # XabcY1234XdefY echo "1234567abcdef" | sed "s/\([0-9]\+\)\([a-z]\+\)/\2\1/" # abcdef1234567 cat unix1.sh | sed 's/#[^!]\+//' # fontos, hogy most ' ' között van a minta (a ! jel miatt kell) cat unix1.sh | sed 's/#\([^!]\+\)/\1/'

echo $PATH | sed "s/:/\n/g" | wc -l

proba=`echo $1 | sed "s/[0-9]//g" if [ "$proba" != "" ] # írható [ ! -z "$proba" ] then echo "Az első paraméter hibás" exit 1 fi

Egy kidolgozott példa

Részlet a Unix/Linux héjprogramozás c. könyvből

Ami a sed-ből kimaradt

Érdekesség I.

Hogyan lehet a grep-pet megkerülve elérni, hogy csak az adott mintára illeszekedő sorokat írjuk ki?
cat f1 | sed -n "/PATTERN/p"
Ahol a PATTERN tetszőleges szabályos kifejezés lehet

Érdekesség II.

Hasonló módon meg tudjuk csinálni grep nélkül azt is, hogy csak azokat a sorokat írjuk ki, amik NEM illeszkednek az adott mintára
cat f1 | sed -n "/PATTERN/d"*

Minden sor elejére beszúrunk egy "> "-t

sed "s/^/> /" f1

Beszúrás: i (insert)

  • Be tudunk szúrni egy megadott szöveget minden sor elé
    cat f1 | sed "i Hello"
  • Ugyanezt megtehetjük bizonyos sorokkal
    cat f1 | sed "3i Hello" # Csak a 3. sor elé szúrja be
  • Összekombinálva a szűrési lehetőségge
    cat f1 | sed "/[0-9]\+/ i A következő sorban szám is van:"

Hozzáfűzés: a (append)

Ugyanazok a lehetőségek mint az előbb, csak itt az adott sor mögé tudunk beszúrni

További sed érdekességek

  • sed "s/$/EOL/"
  • sed "s/^[ \t]*//"
  • sed "s/[ \t]*$//"
  • sed "s/^[ \t]*//;s/[ \t]*$//"
  • sed "s/x/$MIRE/$HANYADIK"
  • sed -r -> Extended RegExp
  • sed "/PATTERN/! s/foo/bar/g"
  • sed "$d" -> utsó sor törlése

Lépésenként kidolgozott példa: Írjuk ki a legnagyobb A vagy a betűvel kezdődő filet!

ls -lR [aA]* ls -lR | grep "^-" ls -lR | grep "^-" | sed "s/[-rwx]* \+[0-9]\+ [a-z]\+ [a-z]\+ *//" ls -lR | grep "^-" | sed "s/[-rwx]* \+[0-9]\+ [a-z]\+ [a-z]\+ *//" | cut -d" " -f1,4- ls -lR | grep "^-" | sed "s/[-rwx]* \+[0-9]\+ [a-z]\+ [a-z]\+ *//" | cut -d" " -f1,4- | grep "[0-9]\+ [Aa].*$" ls -lR | grep "^-" | sed "s/[-rwx]* \+[0-9]\+ [a-z]\+ [a-z]\+ *//" | cut -d" " -f1,4- | grep "[0-9]\+ [Aa].*$" | sort -n ls -lR | grep "^-" | sed "s/[-rwx]* \+[0-9]\+ [a-z]\+ [a-z]\+ *//" | cut -d" " -f1,4- | grep "[0-9]\+ [Aa].*$" | sort -n | tail -n1 ls -lR | grep "^-" | sed "s/[-rwx]* \+[0-9]\+ [a-z]\+ [a-z]\+ *//" | cut -d" " -f1,4- | grep "[0-9]\+ [Aa].*$" | sort -n | tail -n1 | cut -d" " -f2-