Cvičenie č.1 26.2.2016: back to top
Základní příkazy, ovládání shellu.
Trochu podrobněji:
- Editace příkazové řádky: Ctrl-a, Ctrl-e, Ctrl-h, Ctrl-r, kurzorové
šipky i nahoru a dolů, Ctrl-d, Ctrl-k (smaže text od pozice kurzoru do
konce řádku).
-
Příkazy:
man, ls, cd, pwd, cat, more, less
(není standardní), head, tail, wc,
mkdir, rmdir, cp, mv, rm, echo.
- Shellová expanze: *, ?, [výčet], [!výčet], apostrofy a
uvozovky, soubory s názvy začínajícími tečkou.
Příklady:
- Ve svém domovském adresáři vytvořte adresář ADR
- Do tohoto adresáře okopírujte soubory z adresáře
/usr/include, jejichž názvy začínají znakem m, končí
příponou .h a kromě toho v názvu obsahují číslici.
- V adresáři ADR vytvořte podadresář
PODADRESAR.
- Prvních pět řádek z každého z okopírovaných souborů uložte do
souboru ~/ADR/PODADRESAR/prvnichpet.
- Poslední řádky souborů v ~/ADR uložte do souboru
~/ADR/PODADRESAR/posledni.
- Soubory v ~/ADR/PODADRESAR spojte do jednoho souboru
~/ADR/PODADRESAR/prvniaposledni.
- Smažte soubory v ~/ADR/PODADRESAR kromě
prvniaposledni.
- Do souboru ~/ADR/PODADRESAR/pocet uložte počet souborů a
adresářů v ~/ADR.
- Vypište dlouhé informace o adresáři ~/ADR/PODADRESAR, ne jeho
obsah.
- Vymažte obsah souboru ~/ADR/PODADRESAR/prvniaposledni bez
toho, abyste smazali tento soubor.
- Do souboru ~/ADR/PODADRESAR/prvniaposledni přidejte řádku, jež obsahuje
jen znak hvězdičky, tj *.
- Smažte ~/ADR i se všemi soubory a
podadresáři v něm umístěnými.
Řešeníukázatskrýt
#!/bin/sh
# Ve svém domovském adresáři vytvořte adresář ADR
mkdir ~/ADR
# Do tohoto adresáře okopírujte soubory z adresáře
# /usr/include, jejichž názvy začínají znakem 'm', končí
# příponou '.h' a kromě toho v názvu obsahují číslici.
cp /usr/include/m*[0-9]*.h ~/ADR
# V adresáři ADR vytvořte podadresář PODADRESAR.
mkdir ~/ADR/PODADRESAR
# Prvních pět řádek z každého z okopírovaných souborů uložte do
# souboru ~/ADR/PODADRESAR/prvnichpet.
head -n 5 ~/ADR/m*[0-9]*.h >~/ADR/PODADRESAR/prvnichpet
# Poslední řádky souborů v ~/ADR uložte do souboru
# ~/ADR/PODADRESAR/posledni.
tail -n 1 ~/ADR/m*[0-9]*.h >~/ADR/PODADRESAR/posledni
# Soubory v ~/ADR/PODADRESAR spojte do jednoho souboru
# ~/ADR/PODADRESAR/prvniaposledni.
cat ~/ADR/PODADRESAR/* >~/ADR/PODADRESAR/prvniaposledni
# Smažte soubory v ~/ADR/PODADRESAR kromě prvniaposledni.
rm ~/ADR/PODADRESAR/prvnichpet
rm ~/ADR/PODADRESAR/posledni
# Do souboru ~/ADR/PODADRESAR/pocet uložte počet souborů a
# adresářů v ~/ADR.
ls ~/ADR | wc -l >~/ADR/PODADRESAR/pocet
# Vypište dlouhé informace o adresáři ~/ADR/PODADRESAR,
# ne jeho obsah.
ls -ld ~/ADR/PODADRESAR
# Vymažte obsah souboru ~/ADR/PODADRESAR/prvniaposledni bez
# toho, abyste smazali tento soubor.
cp /dev/null ~/ADR/PODADRESAR/prvniaposledni
# Do souboru ~/ADR/PODADRESAR/prvniaposledni přidejte řádku, jež obsahuje
# jen znak hvězdičky, tj *.
echo '*' >>~/ADR/PODADRESAR/prvniaposledni
# Smažte ~/ADR i se všemi soubory a podadresáři v něm umístěnými.
rm -r ~/ADR
Domáca úloha č.1:
- Napište příkaz, který vypíše všechny názvy souborů a adresářů ve vašem
domovském adresáři, které začínají tečkou „.“ a obsahují alespoň 2
znaky kromě tečky. [1 bod]
- Napište příkaz, který vypíše poslední řádku z každého souboru v
adresáři /usr/include, jehož název končí „.h“. [1 bod]
- Napište příkaz, kterým okopírujete všechny soubory z adresáře
/usr/include/, jejichž jména nezačínají číslicí, ale číslici v názvu
obsahují, do vašeho domovského adresáře. [1 bod]
Cvičenie č.2 4.3.2016: back to top
- Vypište řádky číslo 11-20 ze souboru
/etc/passwd
.
- Vytvořte soubor se jménem „-f“, který bude obsahovat jednu řádku s
aktuálním datem. Poté tento soubor smažte.
- Vytvořte soubor „pevne datum“ (tj.
„pevne<mezera>datum“) jehož čas poslední modifikace
bude nastaven na 13:30 1.2. 2009.
- Do svého domovského adresáře okopírujte soubor
/etc/passwd, kopie tohoto souboru se bude jmenovat
ucty a bude mít čas poslední modifikace shodný s časem
poslední modifikace /etc/passwd.
- Nastavte datum poslední modifikace souboru ucty (ve
vašem domovském adresáři) na čas
poslední modifikace souboru /etc/group.
- Napište příkaz, který vypíše obsah adresáře /usr/bin podle jmen sestupně podle abecedy
do souborů
bina a binb a
navíc jej vypíše na obrazovku stránkovaně (pomocí less nebo
more)
- Rozmyslete si, co se děje při následujících příkazech:
mv soubor /dev/null
cp soubor /dev/null
cat soubor >/dev/null
- Vypište deset největších souborů a pak deset nejmenších souborů v
adresáři
/etc
- V adresáři
/usr/bin
najděte soubor, který byl modifikován
naposledy.
Řešeníukázatskrýt
#!/bin/sh
# 1. Vypište řádky číslo 11-20 ze souboru:
head -n20 /etc/passwd | tail -n10
# 2. Vytvoření souboru -f s datem:
date >-f
# Smazání souboru -f:
rm -- -f
# 3. Vytvořte soubor „pevne datum“ (tj. „pevnedatum“) jehož čas poslední modifikace bude nastaven na 13:30 1.2. 2009.
touch -t 200902011330 "pevne datum"
# nebo
touch -d "2009-02-01 13:30:00" "pevne datum"
# 4. Do svého domovského adresáře okopírujte soubor /etc/passwd, kopie tohoto souboru se bude jmenovat ucty a bude mít čas poslední modifikace shodný s časem poslední modifikace /etc/passwd.
cp -p /etc/passwd ucty
# 5. Nastavte datum poslední modifikace souboru ucty (ve vašem domovském adresáři) na čas poslední modifikace souboru /etc/group.
touch -r /etc/group ucty
# 6. Napište příkaz, který vypíše obsah adresáře /usr/bin podle jmen sestupně podle abecedy do souborů bina a binb a navíc jej vypíše na obrazovku stránkovaně (pomocí less nebo more)
ls -r /usr/bin | tee bina binb | more
# 7. smazání, nic, nic:
# 8. Vypište deset největších souborů a pak deset nejmenších souborů v adresáři /etc
ls -S /etc | head
ls -rS /etc | head
# 9. V adresáři /usr/bin najděte soubor, který byl modifikován
# naposledy.
ls -lrt /usr/bin | head -n 1
Domáca úloha č.2 (prosím DO STREDY 9.3.2016 23:59)
- Vypište počet skupin v systému (řádků v
/etc/group) [1 bod]
-
Napište příkaz, kterým nastavíte datum a čas poslední modifikace
souboru na 11.3.1993 15:04. [1 bod]
-
Vypište jméno druhého největšího souboru v adresáři
/usr/bin
. [1 bod]
Cvičenie č.3 11.3.2016: back to top
Práva a jednoduché utility. Pozor, v laboch použite adresár /tmp na skúšanie, pretože tam práva fungujú správne.
Příkazy:
who
,
who am i
, id
, mesg
, write
,
talk
, mail
(mailx
),
last
(tento příkaz není ve specifikaci a není proto
standardní)
chmod
, chgrp
, chown
, file
,
df
, du
, umask
.
- Napište příkaz, který vypíše vaše aktuální UID.
- Napište příkaz, který vypíše seznam skupin, v nichž se
nacházíte.
- Pošlete obsah souboru
/etc/group
mejlem příkazem
mail
.
- Vyzkoušejte si příkaz
df
ke zjištění obsazeného
místa na disku s různými parametry (-k a -P, můžete si zkusit i další,
ale všimněte si, že kromě -t nejsou už další parametry ve
specifikaci).
- Vyzkoušejte si příkaz
du
na adresáři /tmp
nebo na
vašem domovském adresáři s různými parametry (-k
,
-s
, -x
).
- Vytvořte jednoduchý skript a přidělte mu práva pro spuštění.
- Vytvořte soubor, který může vlastník spustit, číst a psát do něj,
členové skupiny jej mohou číst a psát do něj,
ostatní jej mohou jen spustit.
- Zkuste vytvořit skript, který nelze číst, ale má práva na spuštění, zkuste jej spustit.
Proč to u shellového skriptu nejde?
- Vytvořte adresář, do kterého může kdokoli přejít a přidávat soubory, ale
jen vlastník smí vypsat obsah adresáře.
- Vytvořte adresář, do něhož lze přejít, nelze číst jeho obsah a lze
v něm přidávat soubory. Vytvořte v tomto adresáři soubor, k němuž
budete mít práva jen ke čtení a zkuste ho smazat.
- Okopírujte /etc/passwd do /tmp jednak pomocí
cp
,
jednak pomocí cp -p
a koukněte se pomocí ls
-l
, jaký je
mezi těmito kopiemi rozdíl.
- Spusťte si vimtutor cs
Řešeníukázatskrýt
# 1.
id -u
# 2.
id -Gn
# 3.
mail -s "Obsah /etc/group" adresa </etc/group
# 6.
cat >skript.sh <<EOF
#!/bin/sh
echo Ahoj světe
EOF
# potom nastavit prava
chmod a+x skript.sh
# 7.
cat >skript.sh <<EOF
#!/bin/sh
echo Ahoj světe
EOF
chmod 0761 /tmp/skript.sh
# Ekvivalentně například:
chmod u+rwx,g=u-x,o=u-rw /tmp/skript.sh
# nebo
chmod u=rwc,g=rw,o=x /tmp/skript.sh
# 8.
cat >/tmp/skript.sh <<EOF
#!/bin/sh
echo Ahoj světe
EOF
chmod a+x-r /tmp/skript.sh
/tmp/skript.sh
# Aby mohl skript shell spustit, musí jej být schopen přečíst,
# k čemuž musí mít oprávnění.
# 9.
mkdir /tmp/adresar
chmod 0755 /tmp/adresar
# Případně ekvivalentně
chmod u+rwx,go=u-w /tmp/adresar
# 10.
mkdir /tmp/adresar
chmod 0300 /tmp/adresar
# Případně ekvivalentně
chmod u+wx-r,go-rwx /tmp/adresar
touch /tmp/adresar/soubor
chmod 0400 /tmp/adresar/soubor
# Případně ekvivalentně
chmod u+r-wx,go-rwx /tmp/adresar/soubor
rm -f /tmp/adresar/soubor
Domáca úloha č.3 (prosím DO STREDY 16.3.2016 23:59)
-
Napište příkaz, kterým všem souborům v podstromu adresáře
/tmp/adresar
přidáte právo ke čtení všem členům skupiny a současně právo ke čtení
zruší ostatním (tj. těm, kdo nejsou vlastníci ani členové skupiny). [1 bod]
-
Vytvořte soubor a přidělte mu práva tak, aby jej mohl vlastník
spustit, číst i zapisovat do něj, členové skupiny jej mohli spustit a
číst, ostatní jej mohou jen číst. V příkazu
chmod
použijte jednak symbolický zápis práv [1 bod] a jednak octalový zápis
práv [1 bod].
Cvičenie č.4 18.3.2016 back to top
Príkazy:
ln
, diff
, cut
,
paste
, tr
,
sort
.
Príklady:
- Vytvořte ve svém domovském adresáři link na
/etc/passwd
, zkuste
nejprve vytvořit hard link a poté soft link (rozmyslete si, proč hard
link vytvořit nelze). Vyzkoušejte, jak se při ls -l
zobrazí soft link.
- Stáhněte si soubor
calories.csv
, jde o soubor ve formátu CSV,
kde je jako oddělovače sloupců použito středníku.
- V souboru
calories.csv
nahraďte uvozovky pomocí
apostrofů.
-
Ze souboru
calories.csv
odstraňte apostrofy (stejně jako dále předpokládám, že soubor byl změněn předchozími příklady, tedy zde jsou po předchozím příkladu apostrofy na místě původních uvozovek).
-
Ze souboru
calories.csv
vypište jen první sloupec,
tj. sloupec se jmény potravin.
- V souboru
calories.csv
nahraďte velká písmena malými,
ale jen v prvním sloupci. (Postup: Vyříznutí prvního sloupce pomocí
cut
, náhrada pomocí tr
, připojení zpět
pomocí paste
)
- V souboru
calories.csv
nahraďte čárky pomocí pomlčky
a pomocí diff
se podívejte, které řádky byly změněny.
- Soubor
calories.csv
seřaďte podle množství calorií
sestupně, první řádka s hlavičkou musí zůstat na svém místě.
- Soubor
calories.csv
seřaďte podle trojice (protein,
karbohydráty, tuk) vzestupně. První řádek s hlavičkou musí zůstat na svém místě.
- Ze souboru
calories.csv
vypište počet různých
použitých jednotek (druhý sloupec).
- Soubor
calories.csv
upravte tak, aby poslední tři
sloupce byly v opačném pořadí (tj. ve výsledku bude nejprve množství
proteinů, pak karbohydrátů a pak tuků, použijte cut
a
paste
).
- Z výstupu
ls -l
vyberte pouze 9 znaků s právy.
- Předpokládejte, že máte tři soubory,
scitanec1
,
scitanec2
a soucet
, každý z nich obsahuje
stejný počet řádků s čísly. Sestavte tyto řádky do tvaru
scitanec1+scitanec2=soucet
.
- Vypište seznam souborů v aktuálním adresáři ve tvaru
„velikost jméno“, seznam vytvořte úpravou výpisu
ls -l
a ls
.
- Vypište loginy ze souboru
/etc/passwd
po pěti na řádek, na každém
řádku jsou oddělené čárkami.
- BONUS k
ln
: Vytvořte hard link v /tmp
na jiný soubor v
/tmp
. Vyzkoušejte si výpis ls -l a všimněte si, jak se
změnilo číslo v druhém sloupečku. Pomocí ls -i
zkontrolujte,
že obě kopie mají stejné číslo inode.
Riešeniaukázatskrýt
# 1.
# Hard link
ln /etc/passwd ~
# Soft link
ln -s /etc/passwd ~
# 3.
tr \" \' <calories.csv >/tmp/calories.a.csv
mv /tmp/calories.a.csv calories.csv
# 4.
tr -d \' <calories.csv >/tmp/calories.a.csv
mv /tmp/calories.a.csv calories.csv
# 5.
cut -f1 -d\; calories.csv
# 6.
cut -f1 -d\; calories.csv >/tmp/prvni
cut -f2- -d\; calories.csv >/tmp/ostatni
tr '[:upper:]' '[:lower:]' < /tmp/prvni | paste -d\; - /tmp/ostatni >calories.csv
rm /tmp/prvni /tmp/ostatni
# 8.
# Uložíme hlavičku
head -n 1 calories.csv >/tmp/hlavicka
# Zbytek seřadíme a přidáme
tail -n +2 calories.csv | sort -t\; -k4,4nr >>/tmp/hlavicka
mv /tmp/hlavicka calories.csv
# 9.
# Uložíme hlavičku
head -n 1 calories.csv >/tmp/hlavicka
# Zbytek seřadíme a přidáme
tail -n +2 calories.csv | sort -t\; -k7,7n -k6,6n -k5,5n >>/tmp/hlavicka
mv /tmp/hlavicka calories.csv
# 10.
# V prvním řešení rozlišujeme i mezi dvěma jednotkami s různým
# množstvím (tj. např. 1 Cup a 2 Cup jsou brány jako různé)
tail -n +2 calories.csv | sort -t\; -k2,2 -u | wc -l
# Pokud bychom chtěli brát dvě jednotky s různým množstvím jako
# shodné (tj. nechceme například rozlišovat mezi 1 Cup a 2 Cup),
# pak můžeme postupovat následovně:
tail -n +2 calories.csv | cut -f2 -d\; | cut -f2- -d" " | sort -u | wc -l
# 11.
cut -f5 -d\; calories.csv >/tmp/paty
cut -f6 -d\; calories.csv >/tmp/sesty
cut -f7 -d\; calories.csv >/tmp/sedmy
cut -f1-4 -d\; calories.csv | paste -d\; - /tmp/sedmy /tmp/sesty /tmp/paty >/tmp/novy
mv /tmp/novy calories.csv
rm /tmp/paty /tmp/sesty /tmp/sedmy
# 12.
ls -l | cut -c2-10
# 13.
paste -d+= scitanec1 scitanec2 soucet
# 14.
ls -l | tail -n +2 | tr -s " " | cut -d " " -f 5 >/tmp/velikosti
ls | paste -d " " /tmp/velikosti -
rm /tmp/velikosti
# 15.
cut -d: -f1 </etc/passwd | paste -d"," - - - - -
# Alternativně a ekvivalentně lze:
cut -d: -f1 </etc/passwd | paste -s -d",,,,\n" -
Domáca úloha 4 (prosím do stredy 23.3.2016 23:59) riešenia
- V souboru
calories.csv
nahraďte každý
název potraviny (tj. první sloupec)
jediným znakem „-“. Ostatní sloupce zůstanou beze změny. [1 bod]
- Vypište dvojice uid:login za každého uživatele v
/etc/passwd
. [1 bod]
- Určete počet různých států, které se vyskytují v souboru
ip-by-country.csv
. [1
bod]
Cvičenie č.5 1.4.2016 back to top
Príkazy: find
, začiatok
xargs
a grep
.
- V podstromu adresáře
/usr/include
najděte soubory, které jsou v
podstromu adresářů v hloubce alespoň 2 a nejvýš 3.
-
V adresáři
/etc
najděte soubory, které jsou novější než
/etc/passwd
- V podstromu adresáře
/bin
najděte soubory, které
vlastní root a jsou spustitelné jen pro vlastníka a členy skupiny,
nikoli pro ostatní.
- V adresáři
/etc
najděte soubory, které patří skupině
stunnel
a pro každý vypište dlouhé informace pomocí
ls -l
.
- Zkuste rozdíl mezi
echo $PATH; echo "$PATH"; echo '$PATH';
- Zkuste rozdíl mezi
echo *; echo "*"; echo '*';
- Vypište seznam cest obsažených v
$PATH
s tím, že bude
každá na samostatném řádku a ve výpisu nebudou obsažený oddělovací
znaky „:“.
- Vypište dlouhý výpis adresářů obsažených v
$PATH
, lépe řečeno
dlouhé informace o nich, ne jejich obsah
- Zjistěte, ve kterých adresářích uložených v proměnné
$PATH
se vyskytuje program awk
.
- Ze souboru calories.csv vyberte
řádky, v nichž název potraviny obsahuje alespoň tři znaky.
- Napište příkaz, který vypíše všechny (pro vás viditelné) soubory nebo
adresáře, které mají ve jménu podřetězec 'bin' v podstromu aktuálního
adresáře.
- Vypište všechny symbolické linky z adresáře
/etc
,
nezahrnujte celý podstrom, jen to, co je přímo v adresáři
/etc
.
- Z podstromu adresáře
/usr/bin
vypište soubory, na
které ukazují alespoň tři hardlinky.
- V podstromu adresáře
/tmp
najděte všechny soubory, které jsou
větší než sto kilobyte a jsou čitelné pro všechny.
Riešeniaukázatskrýt
# 1.
find /usr/include -path "/usr/include/*/*" ! -path "/usr/include/*/*/*/*"
# Efektivnější řešení s pomocí prune:
find /usr/include -path "/usr/include/*/*/*" -prune -o -path "/usr/include/*/*"
# 2.
find /etc -newer /etc/passwd
# 3.
find /bin -user root -perm -ug+x ! -perm -o+x
# 4.
find /etc -group stunnel -exec ls -l {} +
# 7.
echo $PATH | tr ":" "\n"
# 8.
echo $PATH | tr ":" "\n" | xargs -I{} ls -ld {}
# 9.
echo $PATH | tr ':' '\n' | xargs -I{} find {}/awk -prune 2>/dev/null
# 10.
grep '^"[^;]\{3,\}";' calories.csv
# 11.
find . -name "*bin*" "(" -type d -o -type f ")
# 12.
find /etc -type l '!' -path "/etc/*/*"
# nebo
find /etc/* -prune -type l
# 13.
find /usr/bin -links +3
# 14.
find /tmp -size +100000c -perm -a+r
Domáca uloha 5 (prosím do stredy 6.4.23:59) riešenia
- Napište příkaz, který vypíše počet všech (pro vás viditelných) adresářů
v podstromu
/etc
. [1 bod]
- V podstromu aktuálního adresáře najděte soubory, které mají nulovou velikost. [1 bod]
- V podstromu adresáře
/usr/include
najděte soubory,
jejichž jméno začíná řetězcem "std" a nekončí příponou ".h". [1 bod]
Cvičenie č.6 8.4.2016 back to top
Príkazy: comm
, join
, split
.
- Stáhněte si soubory countrycodes_en.csv a kodyzemi_cz.csv. Obojí jsou soubory ve
formátu CSV, kde je jako oddělovače sloupců použito středníku.
- Ze souborů
countrycodes_en.csv
a
kodyzemi_cz.csv
vytvořte výpis zemí se dvěma sloupci
oddělenými rovnítkem ve tvaru
český název=anglický název (bez uvozovek).
- Vypište názvy souborů, které se nacházejí
/usr/bin
i
v /bin
.
- Vypište čísla skupin, která jsou v
/etc/group
, ale
nejsou použita v /etc/passwd
.
- Rozdělte soubor na kusy po pěti řádcích a pak jej zase spojte do
jednoho souboru.
- Vypište loginy ze souboru
/etc/passwd
do deseti řádků, na každém
řádku jsou loginy oddělené mezerami.
challenge - vytvořte přemenovač souborů
Riešeniaukázatskrýt
# 2.
tr -d '"' <kodyzemi_cz.csv | tail -n +2 | sort -t \; -k1,1 >/tmp/kody_s
tr -d '"' <countrycodes_en.csv | tail -n +2 | sort -t \; -k4,4 >/tmp/codes_s
join -t\; -1 1 -2 4 -o 1.4,2.1 /tmp/kody_s /tmp/codes_s | tr \; = >preklad
rm /tmp/kody_s /tmp/codes_s
# 3.
cut -d: -f4 </etc/passwd | sort > /tmp/uid
cut -d: -f3 </etc/group | sort | comm -23 - /tmp/uid
rm /tmp/uid
# 4.
# Budeme dělit soubor /etc/passwd
# Předpokládáme přitom, že /etc/passwd obsahuje jen tolik záznamů,
# aby se vešly do souborů s dvoupísmennými identifikátory názvu.
split -l5 /etc/passwd kusypasswd
# Spojený soubor uložíme do aktuálního adresáře, protože k zápisu do
# /etc nemáma práva
cat kusypasswd* >passwd
rm kusypasswd*
# 5.
# Předpokládáme, že /etc/passwd obsahuje jen tolik záznamů,
# abychom si vystačili s dvoupísmennými identifikátory souborů.
cut -d":" -f1 /etc/passwd | split -l10 - loginy
paste -d" " loginy*
rm loginy*
# 6.
ls /usr/bin | sort >/tmp/usr_bin
ls /bin | sort | comm -12 - /tmp/usr_bin
rm /tmp/usr_bin
Domáca úloha 6 (prosím do stredy 13.4.23:59) riešenia
- Na základě obsahu souborů countrycodes_en.csv a kodyzemi_cz.csv vypište názvy států,
které se jmenují stejně v angličtině jako v češtině. [1 bod]
- Rozdělte soubor
/tmp/zlobr
na části po 3 řádcích
a potom tyto části poskládejte v opačném pořadí zpátky do zlobra
(/tmp/zlobr
) - tj. když byly v zlobrovi nejprve první 3 řádky hlava1\nhlava2\nhlava3
, pak další 3 telo1\ntelo2\ntelo2
, atd.,
tak na konci budou v zlobrovi poslední 3 řádky hlava1\nhlava2\nhlava3
, předposlední telo1\ntelo2\ntelo2
, atd. [1 bod]
- A. Vytvořte soubor
piskvorky
, který obsahuje 3 řádky:
X O X
O X O
O X O
Zabezpečte, aby hráč X nebo O vyhrál, tj. měl ve výpisu příkazu 3 své znaky za sebou v řádku, sloupci, nebo uhlopříčke (můžou vyhrát i oba).
Můžete použít jenom 1 řádek příkazu, ve kterém máte dovoleno použít (v libovolném počtu) jenom: cat
, echo
, xargs
(+ příslušné přepínače), název souboru (piskvorky
), a kontrolní znaky |
,<
, >
. Jako parametry nelze použít znaky X a O, ani řetězec obsahujíci znaky X nebo O.
Velkost hrací plochy se může změnit, je jenom potřeba aby byla obdélniková / čtvercová. [0.5 bodu]
B. Stejně jak v části A., ale namísto xargs
máte dovoleno použití paste
(+ přepínače) [0.5 bodu]
>
Cvičenie č.7 15.4.2016 back to top
Příkazy:
sed
, ed
, nl
.
- Pomocí sedu vyberte z výpisu
ls -l
jen sloupec s velikostí
souboru.
- Pomocí sedu přetvořte řádky
/etc/passwd
do podoby
uid (login)
.
- Z výstupu
nl /etc/passwd
vypište jen sudé řádky.
- Na začátky lichých řádek souboru
/etc/passwd
vložte
znak „l“, na začátky sudých řádek vložte znak „s“.
- Na začátky desáté až dvacáté řádky souboru
/etc/passwd
přidejte
znak #
.
- Před první řádku vstupního souboru vložte řádku s
#!/bin/sh
.
- Napište skript pro sed, který odstraní ze shellového skriptu
komentáře, přičemž
- Pokud jde o první řádku souboru a pokud tato řádka má formát
^#!.*
,
pak tento komentář neodstraňujte.
- Řádky, kde před
#
není nic než mezery, odstraňte úplně.
- Pokud se před
#
vyskytují nějaké jiné znaky,
odstraňte z řádky vše od prvního výskytu znaku #
(včetně) do konce
řádky.
- Napište skript pro sed, který otočí pořadí řádek na vstupu.
- Mezi každé dvě řádky souboru
/etc/passwd
vložte prázdnou
řádku.
- Napište skript pro sed, který na každé řádce nahradí jednořádkové
komentáře typu
/* ... */
komentářem typu
//...
,
uvažte, že na řádku může být těch jednořádkových komentářů víc a že
kolem komentářů je i obyčejný text. Z jednoho řádku tak vznikne víc
řádek, protože za každým komentářem //
musíte
odřádkovat.
challenge - vytvořte resizer obrázků
Riešeniaukázatskrýt
# 1. v sed
ls -l | sed '1d; s/^\([^ ]* *\)\{5\} .*$/\1/'
# 1. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
ls -l > /tmp/lsl.$$
ed /tmp/lsl.$$<<\KONEC
2,$g/^/s/^\([^ ]* *\)\{5\} .*$/\1/
%p
Q
KONEC
rm /tmp/lsl.$$
# 2. v sed
sed 's/^\([^:]*\):[^:]*:\([^:]*\).*$/\2 (\1)/' /etc/passwd
# 2. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
# Pokud chceme na konci výsledek uložit do souboru, pak tam bude w a q.
cp /etc/passwd /tmp/passwd.$$
ed /tmp/passwd.$$<<\KONEC
g/^/s/^\([^:]*\):[^:]*:\([^:]*\).*$/\2 (\1)/
%p
Q
KONEC
rm /tmp/passwd.$$
# 3. v sed
nl /etc/passwd | sed -n 'n; p'
# 3. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
# Příkaz g provádí následující příkazy na všechny řádky.
# V rámci něj:
# 1) +1p vypíše následující řádku a
# 2) .s/^// odznačí (následující) řádku tak, že ji g vynechá.
# poslední řádku vynecháváme (předpokládáme, že soubor obsahuje aspoň
# dvě řádky), protože u ní by +1 lezlo ven ze souboru.
#
# Kdybychom použili s///, tak místo prázdného regexpu by g doplnilo
# svůj regexp a došlo by k vymazání části sudých řádek. Pokud se neukládají
# změny, tak to nevadí.
nl /etc/passwd > /tmp/passwd.$$
ed /tmp/passwd<<\KONEC
1,$-1g/^/+1p\
.s/^//
Q
KONEC
rm /tmp/passwd.$$
# 4. v sed
nl /etc/passwd | sed -n 'n; p'
#!/usr/bin/sed -f
# Toto je skript pro sed, použití pomocí sed -f
# Volání sed -f <skript> /etc/passwd
s/^/l/
n
s/^/s/
# 4. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
#
# První příkaz přidá znak „l“ na začátek každé řádky.
# Druhý příkaz změní znak „s“ na začátku každé sudé řádky.
# Poté je vypsán výsledek a ed ukončen bez uložení změn.
ed /etc/passwd <<\KONEC
g/^/s/^/l/
1,$-1g/^/+1s/^l/s/
%p
Q
KONEC
# 5. v sed
sed '10,20s/^/#/' /etc/passwd
# 5. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
#
# Změna se neukládá (do /etc/passwd by to nebyl dobrý nápad) a
# výsledek se jenom vypíše na standardní výstup.
ed /etc/passwd <<\KONEC
10,20s/^/#/
%p
Q
KONEC
# 5. v sed
sed '10,20s/^/#/' /etc/passwd
# 5. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
#
# Změna se neukládá (do /etc/passwd by to nebyl dobrý nápad) a
# výsledek se jenom vypíše na standardní výstup.
ed /etc/passwd <<\KONEC
10,20s/^/#/
%p
Q
KONEC
# 6. v sed
#!/usr/bin/sed -f
# Toto je skript pro sed, použití pomocí sed -f
1i\
#!/bin/sh
# 6. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
ed vstupnisoubor <<\KONEC
1i
#!/bin/sh
.
w
q
KONEC
# 7. v sed
#!/usr/bin/sed -f
# Toto je skript pro sed, použití pomocí sed -f
# Přeskočení první řádky, pokud jde o komentář typu #!
1{
/^#!/n
}
# Smazání řádek, kde před # nic není
/^[[:space:]]*#/d
# Odstranění komentáře z ostatních řádek (ignoruje fakt, že # se může
# vyskytovat i v rámci řetězce v uvozovkách a pod., kdybychom toto
# chtěli kontrolovat, bylo by to výrazně komplikovanější).
s/#.*$//
# 7. v ed
# Nejprve vyřídíme vše kromě prvního řádku.
# - První příkaz smaže řádky, které před # nic nemají.
# - Druhý příkaz odstraní z ostatních řádků vše od # dál.
# Poté vyřešíme první řádek.
# - Nejprve vymažeme 1. řádek, pokud obsahuje komentář, který před # nic
# nemá a který napak za # má nějaký znak, který není !.
# - Poté smažeme 1. řádek, pokud obsahuje jen #, za nímž ani před nímž
# nic není. Pokud předchozí příkaz proběhl úspěšně, dostane se sem 2.
# řádek, ale z něj jsme již komentáře odstranili, a tak se nám to
# nemůže splést a další příkazy se pro něj nevykonaly. Z tohoto
# důvodu jsme také nejprve řešili řádky od 2. do posledního.
# - Nakonec z prvního řádku odstraníme vše od prvního # do konce, pokud
# nemá #! na začátku.
# Všude je nutné používat g nebo v, protože jinak by s při neúspěšné
# substituci hlásilo chybu.
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
ed vstupnisoubor.sh <<\KONEC
2,$g/^[[:space:]]*#/d
2,$g/#/s/#.*//
1g/^[[:space:]]*#[^!]/d
1g/^[[:space:]]*#$/d
1v/^#!/s/#.*$//
w
q
KONEC
# 8. v sed
# Vyzkoušíme na nl /etc/passwd, aby bylo vidět opačné pořadí.
nl /etc/passwd | sed -n 'G; $p; h'
# 8. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
# Zpětné lomítko je za příkazem i nutné proto, že jde o příkaz v rámci
# příkazu g, jinak by tam nebylo potřeba.
ed /etc/passwd <<\KONEC
g/^/m0
%p
Q
KONEC
# 9. v sed
# $b zařídí, že se nebude nic přidávat za poslední řádku (při
# poslední řádce se skočí na konec skriptu bez vykonání příkazu a).
# Příkaz a pak provádí samotné přidání nové řádky za aktuální.
sed '$b; a\
' /etc/passwd
# Ekvivalentně lze i pomocí i (adresace zabezpečuje, že se nic nepřidá
# před první řádku):
sed '2,$i\
' /etc/passwd
# 9. v ed
# Všimněte si, že řetězec KONEC je uvozen zpětným lomítkem, to
# proto, aby shell neprováděl expanzi v textu, který za ním píšeme.
# Zpětné lomítko je za příkazem i nutné proto, že jde o příkaz v rámci
# příkazu g, jinak by tam nebylo potřeba.
ed /etc/passwd <<\KONEC
2,$g/^/i\
\
.
%p
Q
KONEC
# 10. v sed
#!/usr/bin/sed -f
# Toto je skript pro sed, použití pomocí sed -f
: zacatek
s%\(.*\)/\*\(.*\)\*/\(.*\)%\1//\2\
\3%
t zacatek
Domáca úloha 7 (prosím do stredy 20.4.2016 23:59) riešenia
VYBERTE si 2 z týchto príkladov, ktoré chcete odovzdať ako DÚ.
(Kľudne pošlite aj tretiu úlohu, opravím ju ale nebude sa rátať do DÚ)
- Pomocí sedu ve vstupním textovém souboru nahraďte výskyty znaků '&',
'<', '>' pomocí jejich HTML entit ('&' pomocí '&',
'<' pomocí '<' a '>' pomocí '>'). [1.5 bodu]
- Pomocí sedu ve vstupním souboru spojte vždy dvě následující řádky
do jedné (tj. odstraňte odřádkování mezi nimi). Ve výsledku tedy bude
spojena 1. s 2. řádkou, 3. se 4. řádkou, 5. s 6. řádkou, atd. [1.5 bodu]
-
Předpokládejte, že řádky vstupního souboru obsahují jen znaky '(' a
')' (tj. na každé řádce je řetězec vyhovující regulárnímu výrazu „[()]*“), vytvořte skript pro sed, který zkontroluje, zda je řetězec na
řádce správně uzávorkovaný. Pokud ano, nahradí řádku řetězcem 'ano', v
opačném případě řetězcem 'ne'. [1.5 bodu]
Cvičenie č.8 22.4.2016 back to top
Příkazy: printf
, read
, řídící struktury (for
,
while
, if
, case
, a pod.),
printf
, expr
, test
,
dirname
, basename
.
- Napište skript, který dostane v parametrech seznam souborů zadaný
cestami, které můžou být i relativní. Ke každému souboru vypíše řádek
s absolutní cestou.
- Napište skript, který přejmenuje všechny soubory v aktuálním
adresáři na soubory se týmž jménem, kde jsou velká písmena změněná
na malá. (Například soubor 'ZALOHA.ZIP' by přejmenoval na
'zaloha.zip')
challenge - vytvořte resizer pro videa
Riešeniaukázatskrýt
# 1.
# Je-li část in ... u for cyklu vynechaná, doplní se in "$@"
for x
do
adresar=$(dirname "$x")
adresar=$(cd $adresar && pwd)
echo $adresar/$(basename $x)
done
# 2.
for x in *[A-Z]*
do
mv "$x" "`echo $x | tr '[:upper:]' '[:lower:]'`"
done
Domáca úloha 8 (prosím do stredy 27.4.2016 23:59) riešenia
- Napište skript, který přejmenuje všechny soubory v aktuálním
adresáři s příponou ".jpeg" na soubory s týmž jménem, ale příponou
".jpg". (Zkuste využít expanze
${proměnná%přípona}
,
sed
, nebo dirname
a basename
.) [1 bod]
- Napište skript, který očekává dva parametry, název souboru a
číslo (označme si ho teď
x
). Ze zadaného souboru řádku číslo x
nahradíme řádkou s obsahem haha
. Použijte shell script
v kterém zavoláte ed
(inspirujte se ed
příkladmi z minulého cvičení, s využitím <<KONEC
pro označení začátku a konce
interaktivního zadávaní příkazů). [1 bod]
- Napište skript, který očekává dva parametry, oba obsahují cestu k
adresářům, zdrojovému a cílovému, přičemž cílový dosud neexistuje. Skript zduplikuje adresářovou
strukturu do cílového adresáře. Soubory v adresářích nekopíruje a
ignoruje je, vytváří jen kopii adresářové struktury. Například
volání
skript /etc ~/etc
by v domovském adresáři vytvořilo podadresář etc, pod ním by byl
stejný podstrom adresářů jako je v /etc
(bez kopií souborů v nich
obsažených). [1 bod]
Cvičenie č.9 29.4.2016 back to top
- Napište skript, který dostane tři parametry, všechny číselné, a vypíše na standardní výstup čísla oddělená mezerami počínaje $1, konče $2 a s krokem $3. Pokud skript dostane jen dva parametry, pak se implicitně použije krok 1.
- Totéž jako předchozí příklad, ale čísla budou každé na zvláštní
řádce a budou zarovnaná na počet míst daný délkou nejdelšího čísla
(tj. délkou $2). Čísla budou zarovnaná nulami na začátku. Tj.
například
skript 0 10 2
by vypsal:
00
02
04
06
08
10
- Napište skript, který přejmenuje všechny soubory v aktuálním
adresáři s příponou jpg na soubory s touž příponou ale s čísly místo
názvů, kde čísla budou zarovnaná na tolik míst, kolik je třeba pomocí
nul. (Využijte toho, co jste už udělali v jednom z předchozích
příkladů.) Tj. například pokud jsou v adresáři soubory alice.jpg,
bob.jpg cyril.jpg a daniel.jpg, přejmenoval by je popořadě skript na
1.jpg, 2.jpg, 3.jpg a 4.jpg. Pokud by těchto souborů bylo alespoň
deset ale méně než 100, byly by pojmenovány jako 01.jpg, 02.jpg,
03.jpg, 04.jpg, ...
-
Napište skript, který očekává na standardním vstupu řádky ve
tvaru:
a+b=c
kde a, b a c jsou čísla, skript načte pro
každou řádku tato tři čísla a zkontroluje, jestli je rovnost správná.
Pokud není správná, ohlásí chybu s číslem řádky, na které k ní došlo.
Na závěr vypíše celkový počet chyb. (Doporučení: Použijte shellový while cyklus s
read a b c
a vhodnou volbou IFS (+=)).
Riešeniaukázatskrýt
# 1.
#!/bin/sh
if [ $# -lt 2 ] || [ $# -gt 3 ]
then
echo Špatný počet parametrů
exit 1
fi
krok=${3:-1}
x=$1
while [ $x -le $2 ]
do
echo $x
x=`expr $x + $krok`
done
# 2.
#!/bin/sh
if [ $# -lt 2 ] || [ $# -gt 3 ]
then
echo Špatný počet parametrů
exit 1
fi
krok=${3:-1}
x=$1
delka=${#2}
while [ $x -le $2 ]
do
printf "%0${delka}d\n" $x
x=`expr $x + $krok`
done
# 3.
#!/bin/sh
x=1
pocet=`ls ./*.jpg | wc -l`
# Tohle je pro případ, že by tam byl nějaký soubor s příponou *.jpg a
# číselným názvem, mohlo by to selhat.
for soubor in *.jpg
do
mv "$soubor" "x$soubor"
done
for soubor in *.jpg
do
mv "$soubor" `printf "%0${#pocet}d\n" $x`.jpg
x=`expr $x + 1`
done
# 4.
#!/bin/sh
IFS="+="
radka=0
while read a b c
do
radka=$(expr $radka + 1)
if [ "$(expr "$a" + "$b")" -ne "$c" ]
then
printf "Chyba na řádce %d (%d+%d<>%d).\n" $radka $a $b $c
fi
done
printf "Počet zkontrolovaných řádek: %d\n" $radka
Domáca úloha 9 (prosím do stredy 4.5.2016 23:59) riešenia
- Napište skript, který očekává na standardním vstupu řádky ve
tvaru 4 slov oddělených mezerami (na každém řádku, kontrolovat vstup nemusíte). Pokud některé řádky budou obsahovat tyto 4 slova (v libovolném pořadí, slova berte case-sensitive tj. velikost písmen přesně takto):
your Windows needs updating
vymažte tyto řádky a zbytek vstupu (zvyšní řádky) vypište na standardní výstup. (Doporučení: Tak jak v úloze 4. z cvičení,
použijte shellový while cyklus s
read
. Pro testování: vícřádkový vstup můžete do vášho skriptu vložit spůsobem: cat vstup | ./skript.sh
kde vstup
je soubor obsahující víc řádků.). [1.5 bodu]
- Napište skript, který očekává tři parametry, soubor, číslo
n a znak c. Pokud třetí parametr chybí, za znak
c je považován mezerník (c=
' '
),
pokud chybí i druhý parametr, uvažuje se navíc n=1.
Skript potom provede cyklický posun doleva řádek podle položek oddělených
znakem c s krokem n. Tj. například při volání
skript /etc/passwd 2 :
by každou řádku tvaru
login:*:uid:gid:jméno:domovský adresář:shell
upravil na řádku tvaru
uid:gid:jméno:domovský adresář:shell:login:*
Při volání
skript vstup 3
a použití na vstupní soubor z první domácé úlohy, tř. ve tvaru:
Čau jak sa máš
your Windows needs updating
Sme kapela Horkíže Slýže
bude výsledek:
máš Čau jak sa
updating your Windows needs
Slýže Sme kapela Horkíže
Upravený soubor vypisuje skript na standardní výstup, soubor zadaný v
parametru neupravuje. [1.5 bodu]
Cvičenie č.10 6.5.2016 back to top
Příkazy:
trap
, ps
, kill
, top
,
sleep
, date
, eval
.
- Podívejte se na výpis
kill -l
, vyskoušejte si: top
, ps
, ps [id]
,
ps -C [process name]
,
ps -C [process name] -o pcpu,pmem
,
ps aux
- Vyskoušejte si spustit proces na pozadí (background process) třeba
top &
a potom ho zastavte kill -9 [pid]
- Napište skript, který se donekonečna zacyklí (
while true; do : done
) ale předtím než to udělá,
vytvoří dočasný soubor temp
. Pomocí trap "rm temp; exit" SIGINT SIGTERM SIGKILL
zabezpečte
ostranení souboru při zastavení skriptu.
- Napište skript, který bude očekávat vstup na standardním vstupu,
načtený vstup pouze zopakuje na svůj standardní výstup. Pokud skript
dostane signál SIGKILL (9), tak samozřejmě skončí, ale pokud dostane
signál SIGTERM (15), SIGQUIT (3), či SIGINT (2) (to je ten, který je
poslán pomocí Ctrl-c), neskončí a jen vypíše číslo toho signálu, který
takto obdržel. Při SIGINT navíc vypíše naposledy vypsanou řádku vstupu.
- Napište skript, který dostane signál a jméno programu, poté pošle
signál všem procesům daného programu. Můžete předpokládat, že se
program jmenuje normálně a název neobsahuje žádné divné znaky (mezeru
ale obsahovat může). (Něco jako
killall
, ale killall
není standardní příkaz.
Doporučuji podívat se na parametr -o
příkazu
ps
. Dále se hodí třeba sed
a xargs
)
- Napište skript, který dostane jeden číselný parametr s počtem
sekund. Skript potom počká zadaný počet sekund a skončí.
Pokud skript obdrží signál SIGINT (2 - Ctrl-C), tak vypíše, kolik
sekund už od začátku uběhlo. Pokud obdrží signál SIGQUIT (3 - Ctrl-\),
tak vypíše, kolik ještě zbývá sekund do konce, ale svůj běh nezastaví.
Pokud skript obdrží signál SIGTERM (15), vypíše, kolik uběhlo sekund od
začátku, kolik zbývá do konce a skončí. Návratová hodnota skriptu je
buď 0, pokud skončil ve správný čas, nebo zbývající počet sekund,
pokud skončil kvůli SIGTERM.
Nepoužívejte date +%s
, %s není standardní součást
formátovacího řetězce pro date. Použijte sleep
v cyklu.
-
Napište skript
cutreorder
, který se bude chovat podobně
jako cut
, bude mít parametry -d
a
-f
, které budou mít týž formát a význam jako u
cut
, v dalších parametrech budou názvy souborů (pokud
nebudou uvedeny, čte se standardní vstup). Rozdíl je v tom, že skript
cutreorder
na výstupu umístí sloupce v pořadí daném
parametrem -f
(v cut
jsou sloupce vypisované
v pořadí, v jakém jsou ve vstupním souboru). Například
-
cutreorder -d : -f 3,1 /etc/passwd
by vypsalo z
/etc/passwd
do dvou sloupců uid:login
.
-
cutreorder -d : -f 3,3-5,1 /etc/passwd
by vypsalo
sloupce uid:uid::gid:full name:login
.
- Napište skript, který dostane jako parametr název souboru, skript očekává poté na standardním vstupu
posloupnost čísel, každé je na nové řádce a je indexem řádky, kterou
má skript vypsat. Skript implementujte tak, že nejprve načte řádky
souboru do pole, které implementujete pomocí eval (tj.
eval
'$'POLE_$INDEX
), poté dotazy zodpovídejte přístupem do tohoto
"pole".
Riešeniaukázatskrýt
# 4.
#!/bin/sh
trap "echo 15" TERM
trap "echo 3" QUIT
trap 'echo 2; echo $x' INT
while read x
do
echo $x
done
# 5.
#!/bin/sh
[ $# -eq 2 ] || {
echo "Očekávám dva parametry, číslo signálu a název programu";
exit 1
}
signal="$1"
program="$2"
ps -e -o pid= -o comm= |\
sed -n 's/^ *\([[:digit:]]\{1,\}\) \{1,\}'"$program"'$/\1/p' |\
xargs kill -$signal
# Případně totéž pomocí while cyklu:
ps -e -o pid= -o comm= | while read pid cmd
do
if [ "$cmd" == "$2" ]
then
kill -$signal $pid
fi
done
# 6.
#!/bin/sh
die() {
echo "$1"
exit 1;
}
# Vystačíme si s hodinami, minutami a sekundami,
# předpokládáme tedy, že interval bude kratší než den a že v čase
# čekání nebude půlnoc.
now() {
# JINÁ MOŽNOST (ne POSIX-compliant ale funkčná na většině UNIX-ů):
# echo $(date +"%s")
vzorec=$(date +"%H \* 3600 + %M \* 60 + %S")
eval expr $vzorec
}
[ $# -eq 1 ] || die "Špatný počet parametrů"
expr "$1" : '[[:digit:]]*$' >/dev/null || die "Parametr není číslo"
start=$(now)
konec=$(expr $start + $1)
trap 'expr $(now) - $start' 2
trap 'expr $konec - $(now)' 3
trap 'expr $(now) - $start; kill $! 2>/dev/null; exit' 15
while [ $(now) -lt $konec ]
do
# JINÁ MOŽNOST:
# sleep 1
sleep $(expr $konec - $(now) ) &
wait $!
[ $? -gt 128 ] && kill $! 2>/dev/null
done
# VYSVĚTLENÍ MOŽNOSTÍ:
# V uvedeném cyklu by stačilo sleep 1, ale proces by se probouzel každou vteřinu.
# sleep $(expr $konec - $(now) ) samo nestačí kvůli TERM, pokud totiž
# dostane proces shellu se skriptem TERM ve chvíli, kdy běží sleep,
# tak nechá nejprve sleep doběhnout a pak teprve zpracuje signál akcí
# danou trap. (To se neprojeví nutně u ctrl-C, protože to dostane sleep
# samo.) Proto je sleep puštěn na pozadí a poté spuštěno čekání, dokud
# sleep nedoběhne. Po wait se zpracuje signál, aby se nekumulovaly
# procesy sleep, je jim poté poslán signál TERM, čímž jsou průběžně
# ukončovány. V případě obsluhy TERM je též zabit poslední sleep
# běžící na pozadí. Test na to, zda wait s kódem větším než 128 je tu
# proto, že wait vrací takové číslo, právě pokud došlo k přerušení
# signálem.
# 7.
#!/bin/sh
# Zpracování parametrů
# defaultně je delim tabelátor
delim=" "
pole=""
for x in 1 2
do
case "$1" in
-d) delim="$2"; shift 2;;
-d?) delim="${1#-d}"; shift;;
-f) pole="$2"; shift 2;;
-f*) pole="${1#-f}"; shift;;
esac
done
if [ "$pole" = "" ]
then
# Není co vypisovat
exit 0
fi
# Test, nemáme-li číst standardní vstup
if [ $# -eq 0 ]
then
set -- -
fi
# Upravíme si pole do tvaru vhodného pro for cyklus
pole="`echo $pole | tr , " "`"
# Zpracování souborů
for soubor
do
cat $soubor | while read radek
do
vysledek=""
# Zpracování jednotlivých položek vstupu a výstupu
for f in $pole
do
if [ -n "$vysledek" ]
then
vysledek="$vysledek$delim"
fi
vysledek="$vysledek$(echo "$radek" | cut -d $delim -f $f)"
done
echo "$vysledek"
done
done
# 8.
#!/bin/sh
[ $# -eq 1 ] || { echo "Špatný počet parametrů"; exit 1; }
pocet=0
while read radka
do
pocet=$(expr $pocet + 1)
eval RADKY_$pocet='"$radka"'
done <"$1"
while read index
do
eval echo '$'RADKY_$index
done
Domáca úloha 10 (prosím do stredy 11.5.2016 23:59) riešenie
- Napište skript pro spouštění příkazu pomocí e-mailu, na
standardní vstup dostane soubor následujícího tvaru:
From:<addr>
Subject:<cmd>
<input>
...
Skript spustí příkaz <cmd> a na standardní vstup mu dá <input>.
Návratový kód (tj. $?) pošle zpět na adresu <addr> v subjectu, v těle mejlu posílaného zpět bude obsah standardního výstupu spuštěného programu.
Upřesnění:
- Místo <addr> je pochopitelně skutečná adresa, místo
<cmd> je skutečný příkaz i s parametry (které by měl shell zpracovat) a místo <input> je
text, který se předá tomu příkazu. Třetí řádka je prázdná.
- Skript nedostane žádné parametry, vstup dostane na standardním
vstupu. Vstup ale musí být dobře ošetřený - zlý formát, i prázdný vstup
- Parametry příkazu jsou uvedené v rámci subjectu, na standardní vstup dostane obsah mejlu od
4. řádky včetně dál.
[3 body]
Cvičenie č.11 13.5.2016: back to top
- Napište awk skript, který vypíše každou desátou řádku vstupu.
- Napište awk skript, který v souboru /etc/passwd převede písmena v
loginech na velká.
- Napište awk skript, který otočí pořadí slov na každé řádce vstupu
(napíše je v opačném pořadí)
- Napište awk skript, který očísluje řádky na vstupu a vypíše je i s
čísly (jako
nl
).
- Napište awk skript, který vypíše tolik náhodných čísel mezi 0 a 1,
kolik dostane zadáno parametrem.
- Napište awk skript, který z výstupu
getent passwd
) vypíše plná jména uživatelů, jejichž login
má tvar čtyři písmena následovaná čtyřmi číslicemi.
- Napište awk skript, který vypíše počet linků, tedy tagů
<a
ve vstupním html souboru.
- Napište awk skript, který dostane na vstupu html soubor a vypíše
adresy, na které se tento soubor odkazuje (to jest za značku <a
href="adresa"> vypíše adresa). Pozor na to, že ta značka může být
rozložena přes víc řádků a můžou tam být kolem
a
,
href
mezery. Volbou vhodného RS a FS si výrazně usnadníte
práci.
- Napište awk skript, který v textu zakomentuje všechny odstavce,
které začínají komentářovým řádkem. (To jest, před druhou a další
řádky tohoto odstavce předřadí komentářový znak.) Znak uvozující
komentář je '#'. Odstavce se oddělují prázdným řádkem.
- Napište awk skript, který vypíše posledních 10 řádků souboru.
- Napište awk skript, který na vstupu očekává soubor ve formátu csv,
tj. na každé řádce jsou položky oddělené čárkami, přičemž je jich na
každé řádce stejně. První řádka obsahuje hlavičku, tj. názvy sloupců,
první sloupec následujících řádků obsahuje název řádku. Na dalších
pozicích jsou čísla. Skript k tomuto vstupu přidá na výstupu nový
sloupec se jménem „Součet“, který na každém řádku bude obsahovat
součet číselných položek na daném řádku. Tj. například ze vstupu
Jméno,body1,body2,body3
Hynek,3,12,9
Jarmila,7,34,1
Vilém,8,27,0
vytvoří na výstupu
Jméno,body1,body2,body3,Součet
Hynek,3,12,9,24
Jarmila,7,34,1,42
Vilém,8,27,0,35
Riešeniaukázatskrýt
# 1.
#!/bin/awk -f
(NR % 10) == 0
# 2.
#!/bin/awk -f
BEGIN { FS=":"; OFS=":" }
{ $1=toupper($1); print }
# 3.
#!/bin/awk -f
{
for (pole = NF; pole > 1; pole --)
{
printf ("%s" OFS, $pole);
}
printf ("%s" ORS, $1);
}
# 4.
#!/bin/awk -f
{
print NR " " $0;
}
# 5.
#!/bin/sh
# Toto je skript, který obaluje awk skript
# Sám dostane počet potřebných parametrů ve svém parametru.
awk -v pocet="$1" 'BEGIN {
srand();
for (i=0; i<pocet; ++i)
{
print rand ();
}
}'
# 6.
#!/bin/awk -f
BEGIN {
FS = ":";
}
$1 ~ /^[[:alpha:]]{4}[0-9]{4}$/ {
print $5;
}
# 7.
#!/bin/awk -f
# Jako RS zvolíme "<", protože podle toho se dělí HTML soubor
# nejvhodněji. Specifikace ani nepřipouští víceznakové RS (v tom
# případě je výsledek nedefinovaný), regexp může být jen ve FS, tak to
# ani jinak nejde.
#
BEGIN {
RS = "<";
pocetAcek = 0;
}
($1 ~ /^a/) {
++ pocetAcek;
}
END {
print pocetAcek;
}
# 8.
#!/bin/awk -f
# Je to trochu komplikovanější, aby to fungovalo i v případě, že není
# href hned za a, ale je mezi tím ještě něco. Jinak by stačilo rovnou
# brát i=1.
BEGIN {
RS = "<";
FS = "=";
}
$1 ~ /^[[:blank:]]*a[[:blank:]]+/ {
i=1
while (i <= NF)
{
if ($i ~ /[[:blank:]]+href[[:blank:]]*$/)
{
split ($(i+1), pole, "[[:blank:]]*\"[[:blank:]]*");
print pole[2]
}
else if ($i ~ />/)
{
break;
}
++i;
}
}
# 9.
#!/bin/awk -f
# Láká sice použít RS="\n\n", ale RS nemůže být víceznakové, a tak to
# tak jednoduše nejde.
BEGIN {
novyodstavec = 1;
komentovat = 0;
}
novyodstavec && $1 ~ /^#/ {
komentovat = 1;
}
! novyodstavec && NF > 0 && komentovat {
$1 = "#" $1
}
NF > 0 {
novyodstavec = 0;
}
NF == 0 {
novyodstavec = 1;
komentovat = 0;
}
{ print }
# 10.
#!/bin/awk -f
BEGIN {
konecBufferu = 0;
}
{
buffer [konecBufferu] = $0;
konecBufferu = (konecBufferu + 1) % 10;
}
END {
if (NR > 0)
{
if (NR < 10)
{
indexVBufferu = 0;
}
else
{
indexVBufferu = konecBufferu;
}
do
{
print buffer[indexVBufferu];
indexVBufferu = (indexVBufferu + 1) % 10;
}
while (indexVBufferu != konecBufferu)
}
}
# 11.
#!/usr/bin/awk -f
BEGIN { FS=","; OFS="," }
FNR == 1 { $(NF+1)="Součet"; print }
FNR > 1 {
$(NF+1)=0
for (i=1; i < NF; i++) {
$NF+=$i
}
print
}
Domáca úloha 11 (prosím do stredy 18.5.2016 23:59) riešenia
-
Napište awk skript, který formátuje soubor po odstavcích do zadaného počtu sloupců (=znaků na řádek). Jednotlivé odstavce jsou od sebe odděleny volným řádkem, tj. několik řádek za sebou tvoří týž odstavec, pakliže mezi nimi není žádná prázdná řádka. Program vždy vezme odstavec a napíše ho na co nejmenší počet řádků tak, aby k přechodu na nový řádek nedocházelo uprostřed slova. Počet sloupců bude zadaný jako parametr předaný pomocí -v. [3 body]
Cvičenie č.12 20.5.2016 back to top
- Napište program na vyhledávání řádek se zadaným textem (1. parametr) v souboru
s příchozí elektronickou poštou (2. parametr). O každém dopisu, v němž program najde nějakou řádku,
je třeba vypsat do záhlaví základní informace (adresu odesílatele, datum a čas doručení a předmět dopisu)
a poté text všech nalezených řádek. Příklad je z knihy Shell v příkladech od L. Forsta, kapitola 6.4, kde najdete řešení i podrobný komentář - doporočuju k přípravě na zkoušku.
Poznámky k zadání: (na cvičení sme měli zjednodušenou verzi - hledání jenom v těle a v subject-e - ale připojím celé zadání):
- Příchozí elektronické dopisy se v UNIXu ukládají každému uživateli chronologicky do jednoho souboru, jehož jméno
bývá uloženo v systémové proměnné
MAIL
. Jednotlivé dopisy jsou od sebe odděleny tak, že dopis začíná zvláštní řádkou ve tvaru
From ...
, za níž následují hlavičky a tělo dopisu.
- Počítejte s tím, že řádka hlavičky s předmětem dopisu může chybět. Dejte pozor také na případné výskyty řádek
ve tvaru
Subject: ...
v těle dopisu. Takové řádky se do vypisovaného záhlaví dopisu nesmí promítnout - tam se smí zobrazit pouze obsah řádky
Subject: ...
, která byla v záhlaví (byla-li tam). Naproti tomu výskyty řádek ve tvaru From ...
v těle dopisu nemusíte uvažovat.
- Zadaný text se hledá i v řádkách s hlavičkami dopisů, může se tedy stát, že nějaké hledané řádky objevíte dříve než předmět dopisu. V úvodní
oddělovací řádce dopisu
From: ...
se naopak text nehledá.
Příklad souboru v kterém jsou uloženy maily:
From adresa_odesilatele datum_a_cas_doruceni
... zacatek hlavicky
Subject : predmet
... dalsi radky hlavicky
prazdna radka oddelujici hlavicku
... text dopisu
Požadovaný tvar výpisu:
==== From adresa_odesilatele datum_a_cas_doruceni predmet_dopisu
... nalezene radky
==== From adresa_odesilatele datum_a_cas_doruceni predmet_dopisu
... nalezene radky
Riešeniaukázatskrýt
Rozdiely bash vs shellvýberappendix bash manuálu
Domáca úloha 12 (prosím do stredy 25.5.2016 23:59) riešenie
- Napište skript
rmexcept
, který očekává n+1
parametrů, kde první parametr je adresář a další parametry jsou
řetězce popisující názvy souborů (může jít o shellové masky)
v tomto adresáři. Skript v zadaném adresáři vymaže všechny soubory,
jejichž názvy nevyhovují maskám zadaným v parametrech.
Soubory, které vyhovují zadaným maskám a názvům, skript nechá beze
změny, přičemž se jich ani netkne (tedy speciálně nebude je přesouvat
mimo a pak zpět).
Například volání
rmexcept . '*.jpg' '*.png'
by v aktuálním adresáři vymazalo všechny soubory, které nemají příponu jpg ani png.
[3 body]
BONUSOVÉ DOMÁCE ÚLOHY (prosím do stredy 25.5.2016 23:59)
- Vytvořte skript pro sed, který na řádce očekává číslo
n
zadané v desítkové soustavě. Na výstup vypíše sed čísla 0, 1, ...,
n, každé na nové řádce. [3 body]
- Napište skript, který ze souborů jejichž názvy jsou zadané v
parametrech, vybere n nejdelších řádek, u každé řádky je
uvedeno pořadí ve vstupním souboru (ve formátu číslo řádky:
řádka), řádky jsou na výstupu uspořádány podle pořadí ve
vstupním souboru (tj. podle toho čísla před dvojtečkou na výstupu).
Parametr n je implicitně 5, nebo může být zadán jako první
jeden až dva parametry pomocí
-n10
, nebo -n
10
(to je pro příklad n=10, tj. syntaxe je stejná jako
třeba u head
). Pokud chybí parametry s názvy souborů, čte
se standardní vstup. Pokud jsou zadány alespoň dva soubory, pak je
výpis nejdelších řádek z každého souboru uvozen názvem souboru.
[3 body]
- Napište skript, který bude ve vstupním textovém souboru provádět
indentaci řádků podle hloubky zanoření daném závorkami. Parametry
skriptu bude název znak indentace c, počet znaků na úroveň
n a seznam souborů (pokud chybí soubory, čte se standardní
vstup). Skript před každou řádku vloží k*n znaků c,
kde k je hloubka zanoření počátku řádku v závorkách, uvažují se kulaté,
hranaté a složené závorky. Pokud jsou před začátkem textu na řádce již
prázdné znaky, tak jsou nejprve odstraněny. Například vstupní
soubor
a ( b
c d [ e ] f [
g h { j (
k ) } l m
n ] o ) p
q r
by volání skriptu s parametrem c='.' a počtem n=1 upravilo do následující podoby:
a ( b
.c d [ e ] f [
..g h { j (
....k ) } l m
..n ] o ) p
q r
Můžete předpokládat, že vstup je správně uzávorkovaný (pokud není, je
chování nedefinované). Dá se očekávat, že znakem může být mezera nebo
tabelátor.
[3 body]
- Napište skript, který dostane počet sekund sec a
název programu prg a poté následují argumenty, které je třeba
programu předat. Skript spustí program a poté čeká, než skončí, pokud
program neskončí do zadaného limitu daného parametrem sec,
pak skript program ukončí odesláním signálu TERM. Poté počká 5 sekund
a pokud ani poté program neskončil, pošle mu signál KILL, kterým
program zabije.
Pro jednoduchost můžete předpokládat, že interval daný počtem
nezasahuje přes půlnoc do dalšího dne. [3 body]