Programování v shellu
awk

Lukáš Bařinka

Náplň cvičení

Cílem cvičení jsou textové transformace pomocí příkazu awk.

  • Příkaz awk
  • Prostředí
  • Vzory
  • Akce

Příkaz awk

  • awk = Aho Weinberger Kernighan
  • pattern { action }
  • Pro řádku vstupu odpovídající vzoru se provedou akce
  • Části skriptu se oddělují ; nebo novým řádkem
  • Skript může být uložený v souboru (přepínač -f)
  • Prázdný skript
    
    									~alias 100='printf "$(echo %4d{,,,,,,,,,})\n" {1..100}'
    
    									~100 | awk ''
    									~100 | awk -f /dev/null
    								
  • Prázdný vzor
    
    									~100 | awk '{ print $1 }'
    								
  • Prázdná akce
    
    									~100 | awk '0'
    									~100 | awk '1'
    								

   1    2    3    4    5    6    7    8    9   10
  11   12   13   14   15   16   17   18   19   20
  21   22   23   24   25   26   27   28   29   30
  31   32   33   34   35   36   37   38   39   40
  41   42   43   44   45   46   47   48   49   50
  51   52   53   54   55   56   57   58   59   60
  61   62   63   64   65   66   67   68   69   70
  71   72   73   74   75   76   77   78   79   80
  81   82   83   84   85   86   87   88   89   90
  91   92   93   94   95   96   97   98   99  100
						

Prostředí awk

  • Postupně jsou načítány soubory nebo standardní vstup
  • Vstup se rozdělí na záznamy (RS, NR)
  • Záznam se rozdělí na položky (FS, NF, $0, $1, $...)
  • Oddělovač položek (FS) lze nastavit přepínačem -F
  • Řetězce jsou v ""
Records and Fields splitting
  • Výchozí RS="\n" ORS="\n" FS='[ \t]+' OFS=" "
    
    									~100 | awk '{ print $1,$2,$3 }'
    									~100 | awk '{ print $3,$1,$2 }'
    									~100 | awk '{ print NR,NF }'
    									~100 | awk '{ print $NF }'
    									~100 | awk '{ print $NF/3 }'
    									~100 | awk '{ print $(NF/3) }'
    								
  • Změna FS
    
    									~100 | awk -F5 '{ print $1 }'
    									~100 | awk '{ FS=5; print $1 }'
    									~100 | awk '{ FS="5 "; print $1 }'
    									~100 | awk -F '5 ' '{ print $1 }'
    									~100 | awk -F '5\\>' '{ print $1 }'
    								

   1    2    3    4    5    6    7    8    9   10
  11   12   13   14   15   16   17   18   19   20
  21   22   23   24   25   26   27   28   29   30
  31   32   33   34   35   36   37   38   39   40
  41   42   43   44   45   46   47   48   49   50
  51   52   53   54   55   56   57   58   59   60
  61   62   63   64   65   66   67   68   69   70
  71   72   73   74   75   76   77   78   79   80
  81   82   83   84   85   86   87   88   89   90
  91   92   93   94   95   96   97   98   99  100
						
  • Změna výstupních oddělovačů
    
    									~100 | awk '{ print $3 "." $2 "." $1 }'
    									~100 | awk '{ OFS="."; print $3,$2,$1 }'
    									~100 | awk '{ OFS="."; ORS="--"; print $3,$2,$1 }'
    									~100 | awk '{ OFS="." OFS; ORS="-" ORS; print $3,$2,$1 }'
    								

Vzory

  • Akce lze omezit pomocí vzorů pouze na určité záznamy/řádky:
    • prázdný vzor odpovídá každé řádce
    • LE - pravdivý logický výraz
    • /RE/ - řádka odpovídající regulárnímu výrazu
    • od,do - rozsah řádků (včetně)
    • BEGIN - před zpracováním vstupu
    • END - po zpracování vstupu
  • Prázdný vzor = všechny řádky
    
    									~100 | awk '{ print $5 }'
    								
  • Logický výraz
    
    									~100 | awk '0'
    									~100 | awk '1'
    									~100 | awk 'NR == 5'
    									~100 | awk 'NR == 5; NR == 7'
    									~100 | awk 'NR < 5'
    									~100 | awk 'NR % 2'
    									~100 | awk 'NR % 2 && NR < 5'
    									~100 | awk '$1 > 50'
    								
  • Regulární výraz
    
    									~100 | awk '/ 5 /'
    									~100 | awk '/ 5+ /'
    									~100 | awk '!/ 5+ /'
    									~100 | awk '$3 ~ /^[37]/'
    									~100 | awk '$3 !~ /^[37]/'
    								
  • Rozsah
    
    									~100 | awk 'NR >= 5 && NR <= 8'
    									~100 | awk 'NR == 5,NR == 8'
    									~100 | awk 'NR == 5,/80/'
    								
  • BEGIN
    
    									~100 | awk 'BEGIN { ORS="|" }; { print }'
    									~100 | awk 'BEGIN { OFS=":"; i=10 }; { print i--,$0 }'
    								
  • END
    
    									~100 | awk 'END { print NR }'
    									~100 | awk 'END { print $0 }'
    									~100 | awk '{ c += $NF }; END { print c }'
    									~100 | shuf
    									~100 | shuf | awk '
    									NR == 1   { max = $NF }
    									$NF > max { max = $NF }
    									END       { print max }
    									'
    								

Akce

  • Příkazy jsou uzavřeny ve { ... }
  • Jednotlivé příkazy jsou odděleny ; nebo novým řádkem
  • Prázdná akce = výpis zpracovávaného záznamu
  • Implicitní akce/argumenty
    
    									~100 | awk 'NR == 5'
    									~100 | awk 'NR == 5 { print }'
    									~100 | awk 'NR == 5 { print $0 }'
    
    									~100 | awk '{ print length }'
    									~100 | awk '{ print length() }'
    									~100 | awk '{ print length($0) }'
    								
  • Funkce
    
    									~100 | awk '{ print rand() }'
    									~100 | awk '{ print rand() }'
    									~100 | awk 'BEGIN { srand() }; { print rand() }'
    									~100 | awk 'BEGIN { srand() }; { print rand() }'
    									~100 | awk 'BEGIN { srand() }; { print $(NF*rand()+1) }'
    									~100 | awk '
    									BEGIN { srand() }
    									      { print substr($0,length*rand()+1,6) }
    									'
    								
  • Náhrady (substituce)
    
    									awk '{ count = sub ( "RE", "text", source ) } '
    									awk '{ count = gsub ( "RE", "text", source ) } '
    									awk '{ result = gensub ( "RE", "text", "g", source ) } '