Shell Prakticky
Filtry

Lukáš Bařinka

Cíl

Cílem je vyzkoušet si prakticky,
jak funguje přesměrování vstupu a výstupu a textové filtry.

Obsah

  • Přesměrování
  • Příkaz getent
  • Jednoduché textové filtry

Část 1

Přesměrování

Úloha 01

V domovském adresáři vytvořte adresář scripts a v něm vytvořte skript jménem output, který vypíše 5 řádek (čísla od 1 do 5) na standardní výstup a 3 řádky (písmena a, b, c) na chybový výstup.


							~mkdir ~/scripts
							~vim ~/scripts/output

							#!/bin/bash
							printf '%s\n' {1..5}
							printf '%s\n' {a..c} >&2
						

Úloha 02

Pomocí příkazu: chmod +x jméno_souboru, přidejte právo spustitelnosti souboru a skript spusťte.


							~chmod +x ~/scripts/output
							~~/scripts/output
						

Úloha 03

Zařiďte, aby bylo možné spouštět skript pouze jménem bez cesty a spusťte ho.


							#1
							~alias output=~/scripts/output
							~output

							#2
							~PATH=$PATH:~/scripts
							~output
						

Úloha 04

Spojte standardní a chybový výstup skriptu output a uložte jej do souboru all v domovském adresáři a zároveň do terminálu vypište počet řádek výstupu skriptu.


							~output 2>&1 | tee ~/all | wc -l
						

Úloha 05

Přidejte standardní výstup skriptu output do souboru all a chybový výstup zahoďte, zároveň do terminálu vypište počet přidaných řádků do souboru.


							~output 2>/dev/null | tee -a ~/all | wc -l
						

Úloha 06

Přidejte chybový výstup skriptu output do souboru all a standardní výstup zahoďte, zároveň do terminálu vypište počet přidaných řádků do souboru.


							~output 2>&1 >/dev/null | tee -a ~/all | wc -l
						

Část 2

Příkaz getent

  • Name Service Switch
    
    									~less /etc/nsswitch.conf
    									~man nsswitch.conf
    									~cat /etc/hosts
    								
  • Výpis položek (get entries)
    
    									~getent hosts localhost osboxes
    									~ping osboxes
    									~getent hosts google.com
    									~getent passwd
    									~getent group
    								
  • Vlastní obsah (funkce)
    
    									~git clone https://gitlab.fit.cvut.cz/barinkl/uos-workbench.git
    									~getent()
    									{
    									  case $1 in
    									    passwd)
    									      cat ~/uos-workbench/passwd
    									      ;;
    									    group)
    									      cat ~/uos-workbench/group
    									      ;;
    									    *)
    									      command getent "$@"
    									      ;;
    									  esac
    									}
    								

Část 2

Jednoduché textové filtry

Úloha 07

Rozdělte soubor all na poloviny a uložte je do souborů s1 a s2.

Na Solarisu používejte raději GNU verze příkazů z adresáře /usr/gnu/bin


							~lines=$( wc -l <~/all )
							~(( lines=lines/2 ))

							#1
							~head -n "$lines" all > s1
							~tail -n "$lines" all > s2

							#2
							~split -a 1 --numeric-suffixes=1 -l "$lines" all s
							~# gsplit -a 1 --numeric-suffixes=1 -l "$lines" all s
						

Úloha 08

Porovnejte, zda jsou soubory s1 a s2 stejné a pokud ano, vypište text: files are the same .


							~cmp s1 s2 && echo "files are the same"
						

Úloha 09

Z výpisu příkazu getent passwd na počítači fray1 vypište pouze 5. sloupec (se jménem uživatele) a výsledek uložte do souboru jmena .


							~ssh fray1.fit.cvut.cz 'getent passwd' | cut -d: -f5 > jmena
						

Úloha 10

Pokud má soubor jmena alespon 10000 řádků, vypište text:
File 'jmena' OK .


							~(( $( wc -l <jmena ) >= 10000 )) && echo "File 'jmena' OK"
						

Úloha 11

V souboru jmena jsou prázdné řádky, odstraňte je pomocí příkazů sort a tail (případně jinak).


							#1
							~sort jmena | cat -n | head
							~sort jmena | tail -n +7 >jmena2; mv jmena{2,}

							#2
							~grep -v '^$' jmena >jmena2; mv jmena{2,}
						

Úloha 12

Pomocí příkazu grep ' student$' soubor a
grep ' zam$' soubor vytvořte soubory jmena.stu a jmena.zam obsahující pouze studenty, resp. zaměstnance.


							~grep ' student$' jmena >jmena.stu
							~grep ' zam$' jmena >jmena.zam
						

Úloha 13

Pomocí (GNU verze) příkazu wc zjistěte, který soubor obsahuje nejdelší řádek. Jméno takového souboru uložte do proměnné LONG. V případě shody vyberte libovolný soubor.


							~
							~S=$(/usr/gnu/bin/wc -L <jmena.stu)
							~Z=$(/usr/gnu/bin/wc -L <jmena.zam)
							~LONG=jmena.zam
							~(( S>Z )) && LONG=jmena.stu
						

Úloha 14

Vypište nejdelší řádku ze souboru z proměnné LONG a spočítejte, z kolika částí se skládá jméno uživatele.

Řešení pomocí jednoduchých filtrů je komplikované, pokročilejší filtry (probírané později) řešení výrazně zjednoduší.

  1. Nahraďte v souboru všechny znaky kromě nového řádku za libovoný znak (třeba tečku).
  2. Očíslujte řádky výstupu.
  3. Seřaďte výstup podle abecedy tak, aby nejdelší řádek byl první (pozor na číslo řádky).
  4. Vypište pouze první řádek.
  5. Z tohoto řádku vypište pouze první sloupec, tj. číslo řádky. Číslo řádky je od zbytku odděleno tabulátorem.
  6. Toto číslo uložte do proměnné L .
  7. Ze souboru v proměnné LONG vypsat řádku číslo L .
  8. Na této řádce spočítat počet slov jména (pozor na student/zam).

							#1
							~tr -c '\n' '[.*]' <"$LONG"
							~/usr/gnu/bin/tr -c '\n' . <"$LONG"
							#2
							~tr -c '\n' '[.*]' <"$LONG" | cat -n
							#3
							~tr -c '\n' '[.*]' <"$LONG" | cat -n | sort -k 2,2r
							#4
							~tr -c '\n' '[.*]' <"$LONG" | cat -n | sort -k 2,2r | head -n 1
							#5
							~tr -c '\n' '[.*]' <"$LONG" | cat -n | sort -k 2,2r | head -n 1 | cut -f1
							#6
							~L=$( tr -c '\n' '[.*]' <"$LONG" | cat -n | sort -k 2,2r | head -n 1 | cut -f1 )
							#7
							~head -n "$L" "$LONG" | tail -1
							#8
							~echo $(( $( head -n "$L" "$LONG" | tail -1 | wc -w ) - 1 ))
						

Úloha 15

Znamená konec předchozího příkladu, že jsme našli jméno složené z nejvíce slov?


							# Ne, nejdelší řadek nemusí nutně obsahovat nejvíce slov.
							L=$( tr -dc ' \n' <"$LONG" | tr ' ' . | cat -n | sort -k2,2 | tail -n 1 | cut -f1 )

							# Pro netrpělivé, představa o délkách řádků a počtu slov ve jméně:
							~awk 'NF>=max { max=NF; print NF-1,length,$0 }' jmena.zam jmena.stu
						

Úloha 16

Pomocí příkazu awk 'NF==3' soubor ponechte v souborech jmena.stu a jmena.zam pouze ty, které obsahují pouze jedno jméno a příjmení.


							~awk 'NF==3' jmena.stu >jmena.stu2; mv jmena.stu{2,}
							~awk 'NF==3' jmena.zam >jmena.zam2; mv jmena.zam{2,}
						

Úloha 17

Spojte soubory jmena.zam a jmena.stu opět do jednoho souboru jmena .


							~cat jmena.{zam,stu} >jmena
						

Úloha 18

Ověřte, že velikost souboru jmena je přesným součtem velikostí souborů jmena.zam a jmena.stu . Pokud ne, vypište text:
Join failed!


							~J=$( wc -c <jmena )
							~S=$( wc -c <jmena.stu )
							~Z=$( wc -c <jmena.zam )
							~(( J==S+Z )) || echo 'Join failed!'
						

Úloha 19

Pomocí příkazu grep -v 'docasne konto' soubor odstraňte ze souboru jmena řádky dočasných studentských kont.


							~grep -v 'docasne konto' jmena >jmena2; mv jmena{2,}
						

Úloha 20

Do souboru jmena2 uložte pouze příjmení a jména (v tomto pořadí) ze souboru jmena .


							~cut -d' ' -f1 jmena >j
							~cut -d' ' -f2 jmena >p
							~paste -d' ' p j >jmena2
						

Úloha 21

Vypište a zároveň spočítejte jména, která jsou zároveň jako příjmení v souboru jmena2 . Pro výpis na chybový výstup můžete použít speciální soubor /dev/stderr .


							~cut -d' ' -f1 jmena2 | sort -u >p
							~cut -d' ' -f2 jmena2 | sort -u >j
							~comm -12 j p | tee /dev/stderr | wc -l
						

Úloha 22

Ze souboru jmena2 vypište seznam 5 nejčastějších křestních jmen a příjmení oddělených dvojtečkou. Seznamy budou vnitřně oddělené čárkou. Tedy výstup bude jm1,jm2,jm3,jm4,jm5:př1,př2,př3,př4,př5 .


							~P=$( cut -d' ' -f1 jmena2 | sort | uniq -c | sort -k1,1nr | head -n 5 | tr -dc '[:alpha:]\n' | paste -d, -s )
							~J=$( cut -d' ' -f2 jmena2 | sort | uniq -c | sort -k1,1nr | head -n 5 | tr -dc '[:alpha:]\n' | paste -d, -s )
							~printf '%s:%s\n' "$J" "$P"