Programování v shellu
Textové filtry

Lukáš Bařinka

Náplň cvičení

Cílem cvičení je zpracování textu pomocí jednoduchých filtrů.

  • Přesměrování vstupů a výstupů
  • Rozdělování a spojování
  • Řazení a duplicity
  • Rozdíly a verzování

Přesměrování vstupu a výstupu

  • Každý spuštěný program má otevřen 1 vstup a 2 výstupy:
    • stdin: <, 0<
    • stdout: >, 1>
    • stderr: 2>
  • Na pořadí přesměrování záleží, zpracovává se zleva doprava
  • Duplikace FD pomocí >&n
  • Přesměrování výstupů do různých souborů
    
    									~touch {a..e}
    									~ls ? foo >out 2>err
    									~head ???
    								
  • Přesměrování výstupů do stejného souboru
    
    									~ls ? foo >com 2>com
    									~head ???
    								
  • Spojení výstupů pomocí duplikace file-descriptoru
    
    									~ls ? foo >com 2>&1
    									~head ???
    									~ls ? foo 2>&1 >com
    								
  • Špatné použití souboru pro vstup i výstup
    
    									~date >f
    									~nl f
    									~nl f >f
    									~more f
    								
  • Použití souboru pro mezivýsledek
    
    									~date >f
    									~nl f
    									~nl f >f2
    									~mv f2 f
    									~more f
    								
  • Zpracování stdout spolu se stderr rourou
    
    									~ls ? foo | wc -l
    									~ls ? foo 2>&1 | wc -l
    									~ls ? foo |& wc -l
    								
  • Přehození stdout a stderr
    
    									~ls ? foo | wc -l
    									~ls ? foo 3>&2 2>&1 >&3 | wc -l
    									~ls ? foo bar 3>&2 2>&1 >&3 | wc -l
    								
  • Přesměrování pro celý aktuální shell (zkopírujte)
    
    									~>out 2>err
    									~pwd
    
    									~exec 3>&1 4>&2 >out 2>err
    									~ls ? foo
    									~exec >&3 2>&4
    								
  • Uložení mezivýsledku v rouře
    
    									~ls ? foo | tee int | wc -l
    									~ls ? foo | tee -a int | wc -l
    								
  • /proc/PID/fd - seznam FD
    
    									~ls -l /proc/$$/fd
    
    									~sleep 100 &
    									~ls -l /proc/$!/fd
    
    									~sleep 100 >out 2>err &
    									~ls -l /proc/$!/fd
    								

Co je to filter

  • Všechny programy mají standardní vstup
  • Ne všechny jej čtou
  • Filtry obvykle umí zpracovat také soubory (argumenty)
  • Pokud nejsou zadány argumenty, zpracovávají standardní vstup
  • Pro zpracování standardního vstupu mezi ostatními argumenty se obykle používá -
  • Ne každý příkaz je filter
    
    									~echo adr | mkdir
    									~echo /etc | ls
    									~echo vstup | echo nectu
    								
  • Některé příkazy jsou filtry
    
    									~wc /etc/passwd
    									~cat -n /etc/passwd | wc
    									~wc </etc/passwd
    									~cat -n /etc/passwd | wc - /etc/passwd
    								

Rozdělování a spojování

  • „Vertikální“ dělení a spojování: head, tail, split, cat
  • „Horizontální“ dělení a spojování: cut, paste
  • Spojení na základě hodnoty: join
  • Začátek textu
    
    									~getent passwd | nl | head
    									~getent passwd | nl | head -n 20
    									~getent passwd | nl | head -20
    
    									~getent passwd | nl | head -n -20
    									~getent passwd "$USER" | nl | head -c 20
    								
  • Konec textu
    
    									~getent passwd | nl | tail
    									~getent passwd | nl | tail -n 20
    									~getent passwd | nl | tail -n +20
    								

							~man bash | while read -N 1; do
							sleep .0$((RANDOM%20))
							printf -- '%s' "$REPLY"
							done >x &

							~tail -f x
							^C
							~tail -f x
							^C
						
  • Část textu
    
    									~getent passwd | nl | head -n 25 | tail -n 1
    									~getent passwd | nl | tail -n +25 | head -n 1
    								
  • Rozdělení textu
    
    									~getent passwd | nl | split -l 100
    									~wc -l x*
    									~tail -n 1 "$(ls x* | tail -n 1)" | head -c 6; echo
    								
  • Spojení textu
    
    									~cat x*
    									~cat x* | wc -l
    								
  • Rozdělení textu podle sloupců
    
    									~getent passwd | cut -d : -f 1
    									~getent passwd | cut -d: -f1
    									~getent passwd | cut -d: -f3,1,5
    									~getent passwd | cut -d: -f3-5
    									~getent passwd | cut -d: -f1 | cut -c1
    
    									~alias rev="perl -ne 'chomp;print scalar reverse . \"\n\";'"
    									~getent passwd "$USER"
    									~getent passwd "$USER" | rev
    									~getent passwd "$USER" | rev | cut -d: -f1 | rev
    								
  • Spojení sloupců
    
    									~getent passwd | cut -d: -f1 >f1
    									~getent passwd | cut -d: -f3 >f3
    									~getent passwd | cut -d: -f5 >f5
    
    									~paste -d: f3 f1 f5
    									~getent passwd | cut -d: -f1
    									~getent passwd | cut -d: -f1 | paste -d: -s
    									~getent passwd | cut -d: -f1 | paste -d'::\n' -s
    								
  • Překlad znaků
    
    									~echo "$USER" | tr a-z A-Z
    									~ls -l | tr -s ' '
    									~man bash | tr -cd 'a-zA-Z\n -'
    									~man bash | tr -c '[:alpha:]' '\n'
    									~man bash | tr -cs '[:alpha:]' '\n'
    								
  • Spojení na základě hodnoty
    
    									username:password:uid:gid:gecos-field:home-dir:login-shell
    									groupname:password:gid:user-list
    								
    
    									~getent passwd | cut -d: -f4,5 | sort >users
    									~getent group | cut -d: -f1,3 >groups
    									~cut -d: -f1 groups >g1
    									~cut -d: -f2 groups >g2
    									~paste -d: g2 g1 | sort >groups
    									~join -t: groups users
    									~join -t: users groups
    								

Řazení a duplicity

  • Řazení podle jednoho nebo více kritérií: sort
  • Ostranění duplicit: uniq
  • Počítání duplicit: uniq -c
  • Společné řádky: comm
  • Řazení řádků
    
    									fray1:~getent passwd | cut -d: -f3,5 | sort
    									fray1:~getent passwd | cut -d: -f3,5 | sort -n
    									fray1:~getent passwd | cut -d: -f3,5 | tr : ' ' | fgrep Nov >nov
    									fray1:~getent passwd | cut -d: -f3,5 | tr : ' ' | awk '$3 ~ /Nov/' >nov
    
    									username:password:uid:gid:gecos-field:home-dir:login-shell
    
    									                  UID Jméno Příjmení zařazení
    
    									fray1:~sort -t' ' -k2 nov
    									fray1:~sort -t' ' -k2,2 nov
    									fray1:~sort -t' ' -k2,2 -k1,1 nov
    									fray1:~sort -t' ' -k2,2 -k1,1r nov
    									fray1:~sort -t' ' -k2,2r -k1,1n nov
    
    									fray1:~sort -t' ' -k2r nov | sort -t' ' -k1n
    								
  • Unikátní/duplicitní řádky
    
    									fray1:~cut -d' ' -f2 nov | sort
    									fray1:~cut -d' ' -f2 nov | sort -u
    									fray1:~cut -d' ' -f2 nov | sort | uniq
    									fray1:~cut -d' ' -f2 nov | sort | uniq -d
    									fray1:~cut -d' ' -f2 nov | sort | uniq -c
    									fray1:~cut -d' ' -f2 nov | sort | uniq -c | sort -n
    								
  • Společné/jedinečné řádky
    
    									fray1:~fgrep zam nov | cut -d' ' -f2 | sort -u >zam
    									fray1:~fgrep student nov | cut -d' ' -f2 | sort -u >stu
    									fray1:~comm zam stu
    									fray1:~comm -12 zam stu
    									fray1:~comm -23 zam stu
    								

Rozdíly a verzování

  • Porovnání souborů: cmp, diff
  • Verzování souborů: patch
  • Porovnání binárních/textových souborů
    
    									~printf "%s\n" a b c d e f >v1
    									~printf "%s\n" a b cc d f g h >v2
    									~cmp v1 v2
    								
  • Porovnání textových souborů - změny
    
    									~diff v1 v2
    									~diff -u v1 v2
    									~vimdiff v1 v2
    								
  • Verzování textových souborů
    
    									~diff v1 v2 >p
    									~patch v1 <p
    									~patch -i p v1
    									~diff v1 v2
    									~patch -R v1 <p
    									~diff v1 v2