Programování v shellu 1
Regulární výrazy

Lukáš Bařinka

Náplň cvičení

Cílem cvičení je procvičení regulárních výrazů a příkazu grep.

  • Příkaz grep/egrep/fgrep
  • Atomické výrazy a kotvy
  • Kvantifikátory
  • Syntaxe a rozšířené regulární výrazy

Příkazy grep, egrep, fgrep

  • Filtr grep primárně vypíše řádky, které odpovídají (matching) RE (Regular Expression):
    • grep pro BRE (Basic RE)
    • egrep (grep -E) pro ERE (Extended RE)
    • fgrep (grep -F) pro obyčejné řetězce (Fixed string)
  • GNU verze příkazu podporuje přepínač -o pro výpis „only matching“ části řádku.
  • Základní přepínače
    
    									fray1:~alias grep='/usr/gnu/bin/grep'
    									fray1:~getent passwd | cut -d: -f5 >names
    									fray1:~grep Jan names
    									fray1:~grep -i jan names
    									fray1:~grep -vi jan names
    									fray1:~grep -wi jan names
    									fray1:~grep -wi jan names | wc -l
    									fray1:~grep -cwi jan names
    									fray1:~grep -nwi jan names
    									fray1:~grep -lwi jan names /etc/passwd
    								
  • Příklady použítí přepínačů příkazu grep
    
    									fray1:~ls /home/* 2>/dev/null | grep novak
    									fray1:~tr ':' '\n' <<<"$PATH" | grep -v bin
    									fray1:~info ls 2>/dev/null | grep -i list
    									fray1:~grep -l start /etc/* 2>/dev/null
    									fray1:~grep -c example /usr/man/man1/grep.1
    								
  • Spojení RE: „a zároveň“ (AND)
    
    									fray1:~grep Petr names | grep Jan
    									fray1:~grep Petr names | grep -v student
    									fray1:~grep -v zam names | grep -v student
    									fray1:~grep -v zam names | grep -v student | grep -v host
    									fray1:~... | grep -v host | grep -v dokt
    									fray1:~... | grep -v dokt | grep -v User
    									fray1:~... | grep -v User | grep -v UID
    									fray1:~... | grep -v UID | grep -v Admin
    
    									fray1:~grep -v zam names | grep -v student | grep -v host \
    									| grep -v dokt | grep -v User | grep -v UID | grep -v Admin
    								
  • Spojení RE: „nebo“ (OR)
    
    									fray1:~grep Admin names
    									fray1:~grep UID names
    									fray1:~grep -e Admin names
    									fray1:~grep -e Admin -e UID names
    									fray1:~printf '%s\n' Admin UID User >re
    									fray1:~grep -f re names
    								
  • GNU přepínače
    
    									fray1:~grep --color start /etc/init.d/sendmail
    									fray1:~grep --color -o start /etc/init.d/sendmail
    									fray1:~grep --color -A3 start /etc/init.d/sendmail
    									fray1:~grep --color -B3 start /etc/init.d/sendmail
    									fray1:~grep --color -C3 start /etc/init.d/sendmail
    									fray1:~alias grep='/usr/gnu/bin/grep --color'
    								

Syntaxe regulárních výrazů

Konstrukce RE
Implementace RE

Atomické výrazy a kotvy

  • Regulární výraz se skládá z atomárních RE jejich zřetězením
  • Atomárním výrazem je jeden znak, zapsaný přímo, znak z množiny [...] nebo libovoný znak zapsaný jako .
  • Vstupní řádek se na výstup vypíše, pokud kdekoliv obsahuje řetězec odpovídající zadanému RE
  • Výraz (nebo část) lze ukotvit na začátek nebo konec řádky nebo slova

									fray1:~PATH=/usr/gnu/bin:$PATH
									fray1:~alias grep='grep --color'
									fray1:~alias grep='/usr/gnu/bin/grep --color'
									fray1:~cd /home/courses/BIPS1/public/re
								
  • Kotvy
    
    									fray1:.../regrep word words
    									fray1:.../regrep ^word words
    									fray1:.../regrep word$ words
    									fray1:.../regrep '\<ll' words
    									fray1:.../regrep 'who\>' words
    									fray1:.../regrep '\<who\>' words
    									fray1:.../regrep -w 'who' words
    								
  • Množina znaků
    
    									fray1:.../regrep '^[Ww]ord' words
    									fray1:.../regrep '^[XYZ]' words
    									fray1:.../regrep '^[X-Z]' words
    									fray1:.../reLC_ALL=C grep '^[X-Z]' words
    									fray1:.../regrep '^[[:upper:]]' words
    									fray1:.../regrep '^[^[:alpha:]]' words
    								
  • Libovolný znak
    
    									fray1:.../regrep '.' words
    									fray1:.../regrep -c '.' words
    									fray1:.../rewc -l <words
    									fray1:.../regrep '^$' words
    									fray1:.../regrep -v '.' words
    									fray1:.../regrep '^.$' words
    									fray1:.../regrep '\.' words
    									fray1:.../regrep '^[xyz].$' words
    								

Kvantifikátory

  • Atomární regulární výraz lze opakovat:
    • * — libovolněkrát, nebo vůbec (0,1,2,...)
    • \+ — jednou nebo vícekrát [ERE] (1,2,...)
    • \{n,m\} nm-krát, m lze vynechat
    • \? — volitelně (0,1) [ERE]
  • Libovolněkrát nebo vůbec (0,1,2,...)
    
    									fray1:.../regrep 'xx' words
    									fray1:.../regrep 'x.x' words
    									fray1:.../regrep 'x..x' words
    									fray1:.../regrep 'x...x' words
    									fray1:.../regrep 'x.*x' words
    								
  • Alespoň jedenkrát (1,2,...)
    
    									fray1:.../regrep 'x..*x' words
    									fray1:.../regrep -E 'x.+x' words
    									fray1:.../reegrep 'x.+x' words
    									fray1:.../regrep 'x.\+x' words
    								
  • N až M -krát (n,...,m)
    
    									fray1:.../regrep '^.\{2,3\}$' words
    									fray1:.../reegrep '^.{2,3}$' words
    									fray1:.../regrep '[[:upper:]]\{2,3\}' words
    									fray1:.../regrep '[[:upper:]]\{5,\}' words
    									fray1:.../regrep '[[:upper:]]\{5\}' words
    									fray1:.../regrep '^[[:upper:]]\{2,3\}$' words
    									fray1:.../regrep '^[[:upper:]]\{5,\}$' words
    									fray1:.../regrep '^[[:upper:]]\{5\}$' words
    								
  • Volitelně (0,1)
    
    									fray1:.../reegrep '^O.?[[:upper:]]' words
    								
  • Kvantifikátory pracují v režimu „greedy“
    
    									fray1:.../reegrep --color '^.*' words
    									fray1:.../reegrep --color '^[[:upper:]]{2,}' words
    									fray1:.../reegrep --color '[[:upper:]]+$' words
    									fray1:.../reegrep --color '^[[:upper:]].?[[:upper:]]' words
    								
  • Problém s režimem „greedy“
    
    									fray1:.../regetent passwd | grep '^.*:.*:[1-9][0-9]\{3\}:'
    								
    
    ^       .*
    ↓                                                                                ↓
    ^       .*                                                              :
    ↓                                                                       ↓
    ^       .*                                          :         .*        :
    ↓                                                   ↓                   ↓
    ^       .*          : .* : UID:
    ↓                   ↓    ↓    ↓
    ⋅qq_13_04:##qq_13_04:9125:1001:docasne konto student:/home/stud/qq_13_04:/bin/bash
    ↑        ↑          ↑    ↑
    ^  [^:]* :   [^:]*  : UID:
    								
  • Řešení problému
    
    									fray1:.../regetent passwd | grep '^[^:]*:[^:]*:[1-9][0-9]\{3\}:'
    								

Podvýrazy (skupiny) a
speciální znaky

  • Znak \ mění speciální význam znaků (ruší nebo nastavuje)
  • V BRE/ERE je možné používat podvýrazy (skupiny) pomocí \(...\), resp. (...)
  • V ERE je možné opakovat také podvýrazy (skupiny)
  • Na podvýraz (skupinu) je možné se odvolat pomocí \1 ... \9
  • Speciální/obyčejný význam znaku
    
    									fray1:.../regrep '[error]' apache.log
    									fray1:.../regrep '\[error]' apache.log
    									fray1:.../refgrep '[error]' apache.log
    									fray1:.../regrep -F '[error]' apache.log
    									fray1:.../regrep '.zip' apache.log
    									fray1:.../regrep '\.zip' apache.log
    									fray1:.../refgrep '.zip' apache.log
    								

								Monday Tuesday Wednesday Thursday Friday Saturday Sunday

								January February March April May June July August
								September October November December

								
  • Alternativní výrazy
    
    									grep '[MTWTFS][ouehra][neduit][sneru]*day' words
    									egrep '(Mon|T(ue|hur)s|Wednes|Fri|S(atur|un))day' words
    
    									grep '^[JFMASOND][aepuco][nbrynlgptvc][uarychestmbo]*$' words
    									egrep '^((Jan|Febr)uary|April|Ma(rch|y)|Ju(ne|ly)|'\
    									'August|(Octo|(Sept|Nov|Dec)em)ber)$' words
    								
    • Podvýrazy a jejich opakování
      
      									fray1:.../reegrep '^([[:upper:]].*){5}$' words
      									fray1:.../reegrep '^[^[:upper:]]*([[:upper:]][^[:upper:]]*){5}$' words
      								
    • Podvýrazy a jejich znovupoužití
      
      									fray1:.../regrep '^\(.\)\(.\).\2\1$' words
      									fray1:.../reegrep '^(.)(.).\2\1$' words
      									fray1:.../reinfo bash | grep '\<\([^ ][^ ]*\)\>.*\<\1\>'
      									fray1:.../reinfo bash | egrep '\<([^ ]+)\>.*\<\1\>'