Cílem je vyzkoušet si prakticky,
jak funguje přesměrování vstupu a výstupu a textové filtry.
Přesměrování
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
Pomocí příkazu: chmod +x jméno_souboru
, přidejte právo spustitelnosti souboru a skript spusťte.
~chmod +x ~/scripts/output
~~/scripts/output
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
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
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
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
Příkaz getent
~less /etc/nsswitch.conf
~man nsswitch.conf
~cat /etc/hosts
~getent hosts localhost osboxes
~ping osboxes
~getent hosts google.com
~getent passwd
~getent group
~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
}
Jednoduché textové filtry
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
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"
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
Pokud má soubor jmena
alespon 10000 řádků, vypište text:File 'jmena' OK
.
~(( $( wc -l <jmena ) >= 10000 )) && echo "File 'jmena' OK"
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,}
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
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
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ší.
L
.LONG
vypsat řádku číslo L
.
#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 ))
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
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,}
Spojte soubory jmena.zam
a jmena.stu
opět do jednoho souboru jmena
.
~cat jmena.{zam,stu} >jmena
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!'
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,}
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
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
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"